如何使用骆驼在 java 中以固定长度数据格式编组 JSON 和重复组?

How to marshal JSON with repeating groups in a fixed length data format in java using camel?

我需要处理一个 JSON - 它有重复组 我需要把它转换成定长记录

{
    "blockType" : "BL-H ",
    "blockTypeLength" : "00000031",
    "blockId" : "S62951156229900",
    "totalNoOfTX" : "001",
    "msgblockType" : "TX-S ",
    "messageLength" : "00000728",
    "noa":[
        {
            "title":"Behin",
            "artist":"LIMP ",
            "itunes_link":"http:behind"
        },
        {
            "title":"Alone",
            "artist":"ALYSS",
            "itunes_link":"http:clk.doubler.com"
        }
    ]

}

应转换为 BehinLIMP http:behindAloneALYSShttp:clk.doubler.com

我可以在请求中有一对多这样的组

我试过的-

DataFormat bindy = new BindyFixedLengthDataFormat(myModel.class);

                from("direct:testUnmarshall")
            .log("${body}")
            //.unmarshal().json(JsonLibrary.Jackson, BillingBookingRequest[].class)
            .inputType(BillingBookingRequest.class)
            .process(new Processor() {
                @Override
                public void process(Exchange exchange) throws Exception {

                    try {
                        BillingBookingRequest responseBody = exchange.getMessage().getBody(BillingBookingRequest.class);

                        ZvkkRequest requestBody = new ZvkkRequest();
                        requestBody.setBlockType(responseBody.getBlockType());
                        requestBody.setBlockTypeLength(responseBody.getBlockTypeLength());
                        requestBody.setBlockId(responseBody.getBlockId());
                        requestBody.setTotalNoOfTX(responseBody.getTotalNoOfTX());
                        requestBody.setMsgblockType(responseBody.getMsgblockType());
                        requestBody.setMessageLength(responseBody.getMessageLength());

                        List<DAO> noaList = responseBody.getNoa();
                        List<DAOFix> repGrp = new ArrayList<>();

                        for (DAO noa:
                             noaList) {
                            DAOFix obj = new DAOFix();
                            obj.setArtist(noa.getArtist());obj.setTitle(noa.getTitle());obj.setItunes_link(noa.getItunes_link());
                            repGrp.add(obj);
                        }

                        requestBody.setRepeatingGrp(repGrp);
                        exchange.getOut().setBody(requestBody);
                    } catch (Exception exception){
                        System.out.println("EXCEPTION HERE :: "+exception.getMessage());
                        exception.printStackTrace();
                    }

                }
            })
            .log("Before marshal ....... ${body}")
            .marshal(bindy)
            .log("After marshal ....... ${body}")
            .to("{{file.path}}fileName=check.dat")
            .end();
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
also observed - org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: myFixedLengthRequestModel to the required type: java.io.InputStream with value myFixedLengthRequestModel[with all the values]

我使用了相应的模型来保存 json 的值以及@FixedLengthRecord 需要帮助来理解和解决这个问题。

public class ZvkkRequest {
@DataField(pos = 1, length=5, align = "L", paddingChar=' ')
private String blockType;
@DataField(pos = 2, length=8, align = "R", paddingChar='0')
private int blockTypeLength;
@DataField(pos = 3, length=15, align = "L", paddingChar=' ')
private String blockId;
@DataField(pos = 4, length=3, align = "R", paddingChar='0')
private int totalNoOfTX;
@DataField(pos = 5, length=5, align = "L", paddingChar=' ')
private String msgblockType;
@DataField(pos = 6, length=8, align = "R", paddingChar='0')
private int messageLength;

@OneToMany(mappedTo = "classpath.DAOFix")
private List<DAOFix> repeatingGrp;
}

class DAOFix {

@DataField(pos = 7, length=5, align = "R", paddingChar=' ')
private String title;
@DataField(pos = 8, length=5, align = "R", paddingChar=' ')
private String artist;
@DataField(pos = 9, length=5, align = "R", paddingChar=' ')
private String itunes_link;

}

对此进行了测试,似乎 @OneToMany 似乎无法像 BindyCsvDataFormat 那样与 BindyFixedLengthDataFormat 一起工作,这意味着您可能会处理 json并创建多个对象实例,然后您可以使用 Bindy 将其编组为固定长度的记录。

下面是我用来测试它的代码以及一种方法 (direct:bindyFixedLenghtProcessed) 将单个 ZvkkRequest 实例转换为 ZvkkRequestFixedLenght 实例列表,然后您可以将其编组到BindyFixedLengthDataFormat

public class ExampleTests extends CamelTestSupport {
    
    @Test
    public void bindyCSVTest(){

        // Test bindy @OneToMany with BindyCsvDataFormat 
        template.sendBody("direct:bindyCSV", testJson);
    }

    @Test
    public void bindyFixedLenghtTest(){

        // Test bindy @OneToMany with BindyFixedLengthDataFormat
        template.sendBody("direct:bindyFixedLenght", testJson);
    }

    @Test
    public void bindyFixedLenghtProcessedTest(){

        // Test workaraound 
        template.sendBody("direct:bindyFixedLenghtProcessed", testJson);
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        
        return new RouteBuilder(){

            @Override
            public void configure() throws Exception {
                
                // Doesn't seem to work with OneToMany
                DataFormat bindyCSV = new BindyCsvDataFormat(ZvkkRequest.class);

                from("direct:bindyCSV")
                    .unmarshal().json(JsonLibrary.Jackson, ZvkkRequest.class)
                    .marshal(bindyCSV)
                    .log("${body}");

                DataFormat bindyFixedLenght = new BindyFixedLengthDataFormat(ZvkkRequest.class);

                from("direct:bindyFixedLenght")
                    .unmarshal().json(JsonLibrary.Jackson, ZvkkRequest.class)
                    .marshal(bindyFixedLenght)
                    .log("${body}");

                DataFormat bindyFixedLenght2 = new BindyFixedLengthDataFormat(ZvkkRequestFixedLenght.class);

                from("direct:bindyFixedLenghtProcessed")
                    .unmarshal().json(JsonLibrary.Jackson, ZvkkRequest.class)
                    .process(new Processor(){

                        @Override
                        public void process(Exchange exchange) throws Exception {
                            
                            ZvkkRequest body = exchange.getMessage()
                                .getBody(ZvkkRequest.class);
                            
                            List<ZvkkRequestFixedLenght> requests = new ArrayList<>();

                            for (DAOFix it : body.noa) {
                                ZvkkRequestFixedLenght request = new ZvkkRequestFixedLenght();
                                request.blockType = body.blockType;
                                request.blockTypeLength = body.blockTypeLength;
                                request.blockId = body.blockId;
                                request.totalNoOfTX = body.totalNoOfTX;
                                request.msgblockType = body.msgblockType;
                                request.messageLength = body.messageLength;
                                request.artist = it.artist;
                                request.title = it.title;
                                request.itunesLink = it.itunesLink;
                                requests.add(request);
                            }
                            exchange.getMessage().setBody(requests);
                        }
                        
                    })
                    .marshal(bindyFixedLenght2)
                    .log("${body}");

            }
        };
    }

    String testJson = "{" +
    "    \"blockType\" : \"BL-H \"," +
    "    \"blockTypeLength\" : \"00000031\"," +
    "    \"blockId\" : \"S62951156229900\"," +
    "    \"totalNoOfTX\" : \"001\"," +
    "    \"msgblockType\" : \"TX-S \"," +
    "    \"messageLength\" : \"00000728\"," +
    "    \"noa\":[" +
    "        {" +
    "            \"title\":\"Behin\"," +
    "            \"artist\":\"LIMP \"," +
    "            \"itunes_link\":\"http:behind\"" +
    "        }," +
    "        {" +
    "            \"title\":\"Alone\"," +
    "            \"artist\":\"ALYSS\"," +
    "            \"itunes_link\":\"http:clk.doubler.com\"" +
    "        }" +
    "    ]" +
    "}";
}

bindyFixedLenghtProcessedTest 记录如下:

BL-H 00000031S62951156229900001TX-S 00000728BehinLIMP                    http:behind
BL-H 00000031S62951156229900001TX-S 00000728AloneALYSS          http:clk.doubler.com

如果你想把它们放在 单行 上,你可以尝试分别编组 ZvkkRequestDAOFix 并使用 字符串连接 将未编组的 DAOFix 条目组合成未编组的 ZvkkRequest.

ZvkkRequest.java

@FixedLengthRecord
@CsvRecord(separator=",")
public class ZvkkRequest {
    
    @DataField(pos = 1, length = 5, align = "L", paddingChar = ' ')
    public String blockType;

    @DataField(pos = 2, length = 8, align = "R", paddingChar = '0')
    public int blockTypeLength;
    
    @DataField(pos = 3, length = 15, align = "L", paddingChar = ' ')
    public String blockId;
    
    @DataField(pos = 4, length = 3, align = "R", paddingChar = '0')
    public int totalNoOfTX;
    
    @DataField(pos = 5, length = 5, align = "L", paddingChar = ' ')
    public String msgblockType;
    
    @DataField(pos = 6, length = 8, align = "R", paddingChar = '0')
    public int messageLength;

    @OneToMany
    public List<DAOFix> noa;
}

DAOFix.java

public class DAOFix {

    @DataField(pos = 7, length=5, align = "R", paddingChar=' ')
    public String title;
    
    @DataField(pos = 8, length=5, align = "R", paddingChar=' ')
    public String artist;

    @JsonProperty("itunes_link")
    @DataField(pos = 9, length=30, align = "R", paddingChar=' ')
    public String itunesLink;
}

ZvkkRequestFixedLenght.java

@CsvRecord(separator=",")
@FixedLengthRecord
public class ZvkkRequestFixedLenght {
    
    @DataField(pos = 1, length = 5, align = "L", paddingChar = ' ')
    public String blockType;

    @DataField(pos = 2, length = 8, align = "R", paddingChar = '0')
    public int blockTypeLength;
    
    @DataField(pos = 3, length = 15, align = "L", paddingChar = ' ')
    public String blockId;
    
    @DataField(pos = 4, length = 3, align = "R", paddingChar = '0')
    public int totalNoOfTX;
    
    @DataField(pos = 5, length = 5, align = "L", paddingChar = ' ')
    public String msgblockType;
    
    @DataField(pos = 6, length = 8, align = "R", paddingChar = '0')
    public int messageLength;

    @DataField(pos = 7, length=5, align = "R", paddingChar=' ')
    public String title;
    
    @DataField(pos = 8, length=5, align = "R", paddingChar=' ')
    public String artist;

    @DataField(pos = 9, length=30, align = "R", paddingChar=' ')
    public String itunesLink;
}