This is an automated email from the ASF dual-hosted git repository. jamesnetherton pushed a commit to branch 3.15.x in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
commit 1fdb9ac4bf83390fc5bc64450cf3a9bfea704adf Author: James Netherton <[email protected]> AuthorDate: Mon Oct 14 08:52:00 2024 +0100 Increase BeanIO test coverage --- integration-tests-jvm/beanio/pom.xml | 39 +++ .../component/beanio/it/BeanioResource.java | 254 ++++++++++++++++- .../quarkus/component/beanio/it/BeanioRoutes.java | 95 +++++++ .../component/beanio/it/model/A1Record.java | 59 ++++ .../component/beanio/it/model/AbstractRecord.java | 65 +++++ .../component/beanio/it/model/B1Record.java | 59 ++++ .../beanio/it/model/CustomErrorHandler.java} | 22 +- .../component/beanio/it/model/Employee.java | 110 ++++++++ .../beanio/it/model/EmployeeAnnotated.java | 119 ++++++++ .../quarkus/component/beanio/it/model/Error.java} | 25 +- .../quarkus/component/beanio/it/model/Header.java | 112 ++++++++ .../component/beanio/it/model/Separator.java | 59 ++++ .../quarkus/component/beanio/it/model/Trailer.java | 59 ++++ .../beanio/src/main/resources/complex-mapping.xml | 95 +++++++ .../beanio/src/main/resources/employee-mapping.xml | 63 +++++ .../src/main/resources/single-object-mapping.xml | 28 ++ .../quarkus/component/beanio/it/BeanioTest.java | 301 ++++++++++++++++++++- .../beanio/src/test/resources/complex-data.txt | 12 + .../beanio/src/test/resources/employees-csv.txt | 3 + .../src/test/resources/employees-delimited.txt | 3 + .../src/test/resources/employees-fixedlength.txt | 3 + .../src/test/resources/employees-with-error.txt | 3 + .../beanio/src/test/resources/employees-xml.txt | 42 +++ 23 files changed, 1585 insertions(+), 45 deletions(-) diff --git a/integration-tests-jvm/beanio/pom.xml b/integration-tests-jvm/beanio/pom.xml index a16e03391c..ad83a463ac 100644 --- a/integration-tests-jvm/beanio/pom.xml +++ b/integration-tests-jvm/beanio/pom.xml @@ -35,10 +35,22 @@ <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-beanio</artifactId> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-direct</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-mock</artifactId> + </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy</artifactId> </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-resteasy-jsonb</artifactId> + </dependency> <!-- test dependencies --> <dependency> @@ -51,6 +63,7 @@ <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> + </dependencies> <profiles> @@ -76,6 +89,32 @@ </exclusion> </exclusions> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-direct-deployment</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-mock-deployment</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> </dependencies> </profile> </profiles> diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/BeanioResource.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/BeanioResource.java index 702c15d6a1..1d1d25f48a 100644 --- a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/BeanioResource.java +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/BeanioResource.java @@ -16,35 +16,259 @@ */ package org.apache.camel.quarkus.component.beanio.it; -import jakarta.enterprise.context.ApplicationScoped; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + import jakarta.inject.Inject; -import jakarta.ws.rs.GET; +import jakarta.json.Json; +import jakarta.json.JsonArrayBuilder; +import jakarta.json.JsonObjectBuilder; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.apache.camel.CamelContext; -import org.jboss.logging.Logger; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.quarkus.component.beanio.it.model.A1Record; +import org.apache.camel.quarkus.component.beanio.it.model.B1Record; +import org.apache.camel.quarkus.component.beanio.it.model.Employee; +import org.apache.camel.quarkus.component.beanio.it.model.EmployeeAnnotated; +import org.apache.camel.quarkus.component.beanio.it.model.Error; +import org.apache.camel.quarkus.component.beanio.it.model.Header; +import org.apache.camel.quarkus.component.beanio.it.model.Separator; +import org.apache.camel.quarkus.component.beanio.it.model.Trailer; @Path("/beanio") -@ApplicationScoped public class BeanioResource { + public static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); - private static final Logger LOG = Logger.getLogger(BeanioResource.class); - - private static final String DATAFORMAT_BEANIO = "beanio"; @Inject CamelContext context; - @Path("/load/dataformat/beanio") - @GET + @Inject + ProducerTemplate producerTemplate; + + @Path("/marshal") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.TEXT_PLAIN) + public String marshal(List<Employee> employees, @QueryParam("type") String type) { + return producerTemplate.requestBodyAndHeader("direct:marshal", employees, "type", type, String.class); + } + + @Path("/marshal/annotated") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.TEXT_PLAIN) + public String marshalAnnotated(List<EmployeeAnnotated> employees) { + return producerTemplate.requestBodyAndHeader("direct:marshal", employees, "type", "ANNOTATED", String.class); + } + + @Path("/unmarshal") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + @SuppressWarnings("unchecked") + public Response unmarshal(String data, @QueryParam("type") String type) { + List<Employee> employees = producerTemplate.requestBodyAndHeader("direct:unmarshal", data, "type", type, List.class); + JsonArrayBuilder array = Json.createArrayBuilder(); + for (Employee employee : employees) { + JsonObjectBuilder builder = Json.createObjectBuilder(); + builder.add("firstName", employee.getFirstName()); + builder.add("lastName", employee.getLastName()); + builder.add("title", employee.getTitle()); + builder.add("hireDate", FORMATTER.format(employee.getHireDate())); + builder.add("salary", employee.getSalary()); + array.add(builder.build()); + } + return Response.ok(array.build()).build(); + } + + @Path("/unmarshal/annotated") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + @SuppressWarnings("unchecked") + public Response unmarshalAnnotated(String data) { + List<EmployeeAnnotated> employees = producerTemplate.requestBodyAndHeader("direct:unmarshal", data, "type", "ANNOTATED", + List.class); + JsonArrayBuilder array = Json.createArrayBuilder(); + for (EmployeeAnnotated employee : employees) { + JsonObjectBuilder builder = Json.createObjectBuilder(); + builder.add("firstName", employee.getFirstName()); + builder.add("lastName", employee.getLastName()); + builder.add("title", employee.getTitle()); + builder.add("hireDate", FORMATTER.format(employee.getHireDate())); + builder.add("salary", employee.getSalary()); + array.add(builder.build()); + } + return Response.ok(array.build()).build(); + } + + @Path("/marshal/single/object") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.TEXT_PLAIN) + public String marshalSingleObject(Map<String, String> message) { + return producerTemplate.requestBody("direct:marshalSingleObject", message, String.class); + } + + @Path("/unmarshal/single/object") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + public Map<String, String> unmarshalSingleObject(String message) { + return producerTemplate.requestBody("direct:unmarshalSingleObject", message, Map.class); + } + + @Path("/unmarshal/with/error/handler") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + @SuppressWarnings("unchecked") + public Response unmarshalWithErrorHandler(String data) { + List<Object> results = producerTemplate.requestBody("direct:unmarshalWithErrorHandler", data, List.class); + JsonArrayBuilder array = Json.createArrayBuilder(); + for (Object object : results) { + JsonObjectBuilder builder = Json.createObjectBuilder(); + if (object instanceof Employee) { + Employee employee = (Employee) object; + builder.add("firstName", employee.getFirstName()); + builder.add("lastName", employee.getLastName()); + builder.add("title", employee.getTitle()); + builder.add("hireDate", FORMATTER.format(employee.getHireDate())); + builder.add("salary", employee.getSalary()); + } else if (object instanceof Error) { + Error error = (Error) object; + builder.add("message", error.getMessage()); + builder.add("record", error.getRecord()); + } else { + throw new IllegalStateException("Unsupported type: " + object.getClass()); + } + + array.add(builder.build()); + } + return Response.ok(array.build()).build(); + } + + @Path("/marshal/complex/object") + @POST @Produces(MediaType.TEXT_PLAIN) - public Response loadDataformatBeanio() throws Exception { - /* This is an autogenerated test */ - if (context.resolveDataFormat(DATAFORMAT_BEANIO) != null) { - return Response.ok().build(); + public Object marshalComplexObject() throws Exception { + return producerTemplate.requestBody("direct:marshalComplexObject", createComplexObject(), Object.class); + } + + @Path("/unmarshal/complex/object") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + @SuppressWarnings("unchecked") + public Response unmarshalComplexObject(String data) { + List<Object> results = producerTemplate.requestBody("direct:unmarshalComplexObject", data, List.class); + JsonArrayBuilder array = Json.createArrayBuilder(); + for (Object object : results) { + JsonObjectBuilder builder = Json.createObjectBuilder(); + if (object instanceof Header) { + Header header = (Header) object; + builder.add("identifier", header.getIdentifier()); + builder.add("recordType", header.getRecordType()); + builder.add("date", FORMATTER.format(header.getHeaderDate())); + } else if (object instanceof Separator) { + Separator separator = (Separator) object; + builder.add("value", separator.getValue()); + } else if (object instanceof A1Record) { + A1Record record = (A1Record) object; + BigDecimal price = new BigDecimal(record.getCurrentPrice()); + builder.add("price", price.setScale(2, RoundingMode.HALF_UP).toPlainString()); + builder.add("sedol", record.getSedol()); + builder.add("source", record.getSource()); + } else if (object instanceof B1Record) { + B1Record record = (B1Record) object; + builder.add("securityName", record.getSecurityName()); + builder.add("sedol", record.getSedol()); + builder.add("source", record.getSource()); + } else if (object instanceof Trailer) { + Trailer trailer = (Trailer) object; + builder.add("numberOfRecords", trailer.getNumberOfRecords()); + } else { + throw new IllegalStateException("Unsupported type: " + object.getClass()); + } + + array.add(builder.build()); + } + + return Response.ok(array.build()).build(); + } + + private List<Object> createComplexObject() throws Exception { + String source = "camel-beanio"; + List<Object> complexObject = new ArrayList<>(); + Date date = FORMATTER.parse("2008-08-03"); + Header hFirst = new Header("A1", date, "PRICE"); + Header hSecond = new Header("B1", date, "SECURITY"); + Separator headerEnd = new Separator("HEADER END"); + + A1Record first = new A1Record("0001917", source, 12345.678900); + A1Record second = new A1Record("0002374", source, 59303290.020); + B1Record third = new B1Record("0015219", source, "SECURITY ONE"); + Separator sectionEnd = new Separator("END OF SECTION 1"); + A1Record fourth = new A1Record("0076647", source, 0.0000000001); + A1Record fifth = new A1Record("0135515", source, 999999999999d); + B1Record sixth = new B1Record("2000815", source, "SECURITY TWO"); + B1Record seventh = new B1Record("2207122", source, "SECURITY THR"); + + complexObject.add(hFirst); + complexObject.add(hSecond); + complexObject.add(headerEnd); + complexObject.add(first); + complexObject.add(second); + complexObject.add(third); + complexObject.add(sectionEnd); + complexObject.add(fourth); + complexObject.add(fifth); + complexObject.add(sixth); + complexObject.add(seventh); + + Trailer trailer = new Trailer(7); + complexObject.add(trailer); + return complexObject; + } + + @Path("/split") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + @SuppressWarnings("unchecked") + public Response split(String data) throws Exception { + MockEndpoint mockEndpoint = context.getEndpoint("mock:splitEmployees", MockEndpoint.class); + mockEndpoint.expectedMessageCount(3); + + producerTemplate.sendBody("direct:unmarshalWithSplitter", data); + + mockEndpoint.assertIsSatisfied(5000); + List<Exchange> exchanges = mockEndpoint.getExchanges(); + + JsonArrayBuilder array = Json.createArrayBuilder(); + for (Exchange exchange : exchanges) { + Employee employee = exchange.getMessage().getBody(Employee.class); + JsonObjectBuilder builder = Json.createObjectBuilder(); + builder.add("firstName", employee.getFirstName()); + builder.add("lastName", employee.getLastName()); + builder.add("title", employee.getTitle()); + builder.add("hireDate", FORMATTER.format(employee.getHireDate())); + builder.add("salary", employee.getSalary()); + array.add(builder.build()); } - LOG.warnf("Could not load [%s] from the Camel context", DATAFORMAT_BEANIO); - return Response.status(500, DATAFORMAT_BEANIO + " could not be loaded from the Camel context").build(); + return Response.ok(array.build()).build(); } } diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/BeanioRoutes.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/BeanioRoutes.java new file mode 100644 index 0000000000..766d8a024e --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/BeanioRoutes.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.dataformat.beanio.BeanIODataFormat; +import org.apache.camel.dataformat.beanio.BeanIOSplitter; +import org.apache.camel.quarkus.component.beanio.it.model.CustomErrorHandler; +import org.apache.camel.spi.DataFormat; + +public class BeanioRoutes extends RouteBuilder { + @Override + public void configure() throws Exception { + DataFormat beanIOEmployeeCSV = new BeanIODataFormat("employee-mapping.xml", "employeeCSV"); + DataFormat beanIOEmployeeXML = new BeanIODataFormat("employee-mapping.xml", "employeeXML"); + DataFormat beanIOEmployeeDelimited = new BeanIODataFormat("employee-mapping.xml", "employeeDelimited"); + DataFormat beanIOEmployeeFixedLength = new BeanIODataFormat("employee-mapping.xml", "employeeFixedLength"); + DataFormat beanIOEmployeeAnnotated = new BeanIODataFormat("employee-mapping.xml", "employeeAnnotated"); + + BeanIODataFormat beanIOSingleObject = new BeanIODataFormat("single-object-mapping.xml", "keyValueStream"); + beanIOSingleObject.setUnmarshalSingleObject(true); + + BeanIODataFormat beanIOErrorDataFormat = new BeanIODataFormat("employee-mapping.xml", "employeeCSV"); + beanIOErrorDataFormat.setBeanReaderErrorHandler(new CustomErrorHandler()); + + BeanIODataFormat beanIOComplexObject = new BeanIODataFormat("complex-mapping.xml", "securityData"); + + BeanIOSplitter splitter = new BeanIOSplitter(); + splitter.setMapping("employee-mapping.xml"); + splitter.setStreamName("employeeCSV"); + + from("direct:unmarshal") + .choice() + .when(simple("${header.type} == 'ANNOTATED'")) + .unmarshal(beanIOEmployeeAnnotated) + .when(simple("${header.type} == 'CSV'")) + .unmarshal(beanIOEmployeeCSV) + .when(simple("${header.type} == 'DELIMITED'")) + .unmarshal(beanIOEmployeeDelimited) + .when(simple("${header.type} == 'FIXEDLENGTH'")) + .unmarshal(beanIOEmployeeFixedLength) + .when(simple("${header.type} == 'XML'")) + .unmarshal(beanIOEmployeeXML) + .split(body()) + .setBody().simple("${body}"); + + from("direct:marshal") + .choice() + .when(simple("${header.type} == 'ANNOTATED'")) + .marshal(beanIOEmployeeAnnotated) + .when(simple("${header.type} == 'CSV'")) + .marshal(beanIOEmployeeCSV) + .when(simple("${header.type} == 'DELIMITED'")) + .marshal(beanIOEmployeeDelimited) + .when(simple("${header.type} == 'FIXEDLENGTH'")) + .marshal(beanIOEmployeeFixedLength) + .when(simple("${header.type} == 'XML'")) + .marshal(beanIOEmployeeXML); + + from("direct:unmarshalSingleObject") + .unmarshal(beanIOSingleObject); + + from("direct:marshalSingleObject") + .marshal(beanIOSingleObject); + + from("direct:unmarshalWithErrorHandler") + .unmarshal(beanIOErrorDataFormat); + + from("direct:marshalComplexObject") + .marshal(beanIOComplexObject); + + from("direct:unmarshalComplexObject") + .unmarshal(beanIOComplexObject) + .split(body()) + .setBody().simple("${body}"); + + from("direct:unmarshalWithSplitter") + .split(splitter).streaming() + .to("mock:splitEmployees"); + } +} diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/A1Record.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/A1Record.java new file mode 100644 index 0000000000..b1d7bb7a91 --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/A1Record.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it.model; + +public class A1Record extends AbstractRecord { + Double currentPrice; + + public A1Record() { + } + + public A1Record(String sedol, String source, Double currentPrice) { + super(sedol, source); + this.currentPrice = currentPrice; + } + + public Double getCurrentPrice() { + return currentPrice; + } + + public void setCurrentPrice(Double currentPrice) { + this.currentPrice = currentPrice; + } + + @Override + public int hashCode() { + return currentPrice != null ? currentPrice.hashCode() : 0; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj == this) { + return true; + } else { + A1Record record = (A1Record) obj; + return super.equals(record) && this.currentPrice.doubleValue() == record.getCurrentPrice().doubleValue(); + } + } + + @Override + public String toString() { + return "SEDOL[" + this.sedol + "], SOURCE[" + this.source + "], PRICE[" + this.currentPrice + "]"; + } +} diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/AbstractRecord.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/AbstractRecord.java new file mode 100644 index 0000000000..668a7245d5 --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/AbstractRecord.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it.model; + +public abstract class AbstractRecord { + String sedol; + String source; + + public AbstractRecord() { + } + + public AbstractRecord(String sedol, String source) { + this.sedol = sedol; + this.source = source; + } + + public String getSedol() { + return sedol; + } + + public void setSedol(String sedol) { + this.sedol = sedol; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + @Override + public int hashCode() { + int result = sedol != null ? sedol.hashCode() : 0; + result = 31 * result + (source != null ? source.hashCode() : 0); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj == this) { + return true; + } else { + AbstractRecord abstractRecord = (AbstractRecord) obj; + return sedol.equals(abstractRecord.getSedol()) && source.equals(abstractRecord.getSource()); + } + } +} diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/B1Record.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/B1Record.java new file mode 100644 index 0000000000..051ea6306e --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/B1Record.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it.model; + +public class B1Record extends AbstractRecord { + String securityName; + + public B1Record() { + } + + public B1Record(String sedol, String source, String securityName) { + super(sedol, source); + this.securityName = securityName; + } + + public String getSecurityName() { + return securityName; + } + + public void setSecurityName(String securityName) { + this.securityName = securityName; + } + + @Override + public int hashCode() { + return securityName != null ? securityName.hashCode() : 0; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj == this) { + return true; + } else { + B1Record record = (B1Record) obj; + return super.equals(record) && this.securityName.equals(record.getSecurityName()); + } + } + + @Override + public String toString() { + return "SEDOL[" + this.sedol + "], SOURCE[" + this.source + "], NAME[" + this.securityName + "]"; + } +} diff --git a/integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/CustomErrorHandler.java similarity index 65% copy from integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java copy to integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/CustomErrorHandler.java index ae1ce7fcb6..5dc6112dd5 100644 --- a/integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/CustomErrorHandler.java @@ -14,21 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.quarkus.component.beanio.it; +package org.apache.camel.quarkus.component.beanio.it.model; -import io.quarkus.test.junit.QuarkusTest; -import io.restassured.RestAssured; -import org.junit.jupiter.api.Test; +import org.apache.camel.dataformat.beanio.BeanIOErrorHandler; +import org.beanio.InvalidRecordException; -@QuarkusTest -class BeanioTest { - - @Test - public void loadDataformatBeanio() { - /* A simple autogenerated test */ - RestAssured.get("/beanio/load/dataformat/beanio") - .then() - .statusCode(200); +public class CustomErrorHandler extends BeanIOErrorHandler { + @Override + public void invalidRecord(InvalidRecordException ex) throws Exception { + Error error = new Error(ex.getRecordName(), ex.getMessage()); + handleErrorAndAddAsResult(error); } - } diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Employee.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Employee.java new file mode 100644 index 0000000000..f3bc71cc7c --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Employee.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it.model; + +import java.util.Date; + +public class Employee { + private String firstName; + private String lastName; + private String title; + private int salary; + private Date hireDate; + + public Employee() { + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getSalary() { + return salary; + } + + public void setSalary(int salary) { + this.salary = salary; + } + + public Date getHireDate() { + return hireDate; + } + + public void setHireDate(Date hireDate) { + this.hireDate = hireDate; + } + + @Override + public int hashCode() { + int result = firstName != null ? firstName.hashCode() : 0; + result = 31 * result + (lastName != null ? lastName.hashCode() : 0); + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + salary; + result = 31 * result + (hireDate != null ? hireDate.hashCode() : 0); + return result; + } + + @Override + public boolean equals(Object object) { + if (object == null) { + return false; + } else if (object == this) { + return true; + } else if (!(object instanceof Employee)) { + return false; + } + + Employee e = (Employee) object; + + return this.getFirstName().equals(e.getFirstName()) + && this.getLastName().equals(e.getLastName()) + && this.getTitle().equals(e.getTitle()) + && this.getSalary() == e.getSalary() + && this.getHireDate().equals(e.getHireDate()); + } + + @Override + public String toString() { + return "Employee{" + + "firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", title='" + title + '\'' + + ", salary=" + salary + + ", hireDate=" + hireDate + + '}'; + } +} diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/EmployeeAnnotated.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/EmployeeAnnotated.java new file mode 100644 index 0000000000..7020fae611 --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/EmployeeAnnotated.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it.model; + +import java.util.Date; + +import org.beanio.annotation.Field; +import org.beanio.annotation.Record; + +@Record +public class EmployeeAnnotated { + @Field(at = 0) + private String firstName; + @Field(at = 1) + private String lastName; + @Field(at = 2) + private String title; + @Field(at = 3) + private int salary; + @Field(at = 4, format = "MMddyyyy") + private Date hireDate; + + public EmployeeAnnotated() { + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getSalary() { + return salary; + } + + public void setSalary(int salary) { + this.salary = salary; + } + + public Date getHireDate() { + return hireDate; + } + + public void setHireDate(Date hireDate) { + this.hireDate = hireDate; + } + + @Override + public int hashCode() { + int result = firstName != null ? firstName.hashCode() : 0; + result = 31 * result + (lastName != null ? lastName.hashCode() : 0); + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + salary; + result = 31 * result + (hireDate != null ? hireDate.hashCode() : 0); + return result; + } + + @Override + public boolean equals(Object object) { + if (object == null) { + return false; + } else if (object == this) { + return true; + } else if (!(object instanceof Employee)) { + return false; + } + + Employee e = (Employee) object; + + return this.getFirstName().equals(e.getFirstName()) + && this.getLastName().equals(e.getLastName()) + && this.getTitle().equals(e.getTitle()) + && this.getSalary() == e.getSalary() + && this.getHireDate().equals(e.getHireDate()); + } + + @Override + public String toString() { + return "EmployeeAnnotated{" + + "firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", title='" + title + '\'' + + ", salary=" + salary + + ", hireDate=" + hireDate + + '}'; + } +} diff --git a/integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Error.java similarity index 66% copy from integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java copy to integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Error.java index ae1ce7fcb6..85afd0bf31 100644 --- a/integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Error.java @@ -14,21 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.quarkus.component.beanio.it; +package org.apache.camel.quarkus.component.beanio.it.model; -import io.quarkus.test.junit.QuarkusTest; -import io.restassured.RestAssured; -import org.junit.jupiter.api.Test; +public class Error { + private final String record; + private final String message; -@QuarkusTest -class BeanioTest { + public Error(String record, String message) { + this.record = record; + this.message = message; + } - @Test - public void loadDataformatBeanio() { - /* A simple autogenerated test */ - RestAssured.get("/beanio/load/dataformat/beanio") - .then() - .statusCode(200); + public String getRecord() { + return record; } + public String getMessage() { + return message; + } } diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Header.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Header.java new file mode 100644 index 0000000000..7e1d7c64da --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Header.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it.model; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.dataformat.beanio.BeanIOHeader; + +public class Header implements BeanIOHeader { + String identifier; + String recordType; + Date headerDate; + + public Header() { + } + + public Header(String identifier, Date headerDate, String recordType) { + this.identifier = identifier; + this.headerDate = headerDate; + this.recordType = recordType; + } + + @Override + public int hashCode() { + int result = identifier != null ? identifier.hashCode() : 0; + result = 31 * result + (recordType != null ? recordType.hashCode() : 0); + result = 31 * result + (headerDate != null ? headerDate.hashCode() : 0); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj == this) { + return true; + } else { + Header record = (Header) obj; + return identifier.equals(record.getIdentifier()) && recordType.equals(record.getRecordType()); + } + } + + @Override + public String toString() { + return "TYPE[" + this.recordType + "], IDENTIFIER[" + this.identifier + "]"; + } + + /** + * @return the identifier + */ + public String getIdentifier() { + return identifier; + } + + /** + * @param identifier the identifier to set + */ + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + /** + * @return the headerDate + */ + public Date getHeaderDate() { + return headerDate; + } + + /** + * @param headerDate the headerDate to set + */ + public void setHeaderDate(Date headerDate) { + this.headerDate = headerDate; + } + + /** + * @return the recordType + */ + public String getRecordType() { + return recordType; + } + + /** + * @param recordType the recordType to set + */ + public void setRecordType(String recordType) { + this.recordType = recordType; + } + + @Override + public Map<String, Object> getHeaders() { + Map<String, Object> headers = new HashMap<>(); + headers.put(recordType + "Date", headerDate); + return headers; + } +} diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Separator.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Separator.java new file mode 100644 index 0000000000..78626bbb64 --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Separator.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it.model; + +public class Separator { + String value; + + public Separator() { + } + + public Separator(String value) { + this.value = value; + } + + @Override + public int hashCode() { + return value != null ? value.hashCode() : 0; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj == this) { + return true; + } else { + Separator record = (Separator) obj; + return this.value.equals(record.getValue()); + } + } + + /** + * @return the value + */ + public String getValue() { + return value; + } + + /** + * @param value the value to set + */ + public void setValue(String value) { + this.value = value; + } +} diff --git a/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Trailer.java b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Trailer.java new file mode 100644 index 0000000000..219eb4554e --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/java/org/apache/camel/quarkus/component/beanio/it/model/Trailer.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.beanio.it.model; + +public class Trailer { + int numberOfRecords; + + public Trailer() { + } + + public Trailer(int numberOfRecords) { + this.numberOfRecords = numberOfRecords; + } + + @Override + public int hashCode() { + return numberOfRecords; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj == this) { + return true; + } else { + Trailer record = (Trailer) obj; + return this.numberOfRecords == record.getNumberOfRecords(); + } + } + + /** + * @return the numberOfRecords + */ + public int getNumberOfRecords() { + return numberOfRecords; + } + + /** + * @param numberOfRecords the numberOfRecords to set + */ + public void setNumberOfRecords(int numberOfRecords) { + this.numberOfRecords = numberOfRecords; + } +} diff --git a/integration-tests-jvm/beanio/src/main/resources/complex-mapping.xml b/integration-tests-jvm/beanio/src/main/resources/complex-mapping.xml new file mode 100644 index 0000000000..feab11cff8 --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/resources/complex-mapping.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<beanio xmlns="http://www.beanio.org/2012/03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd"> + <template name="A1Record"> + <field name="sedol" type="string" length="7"/> + <field name="identifier" rid="true" literal="A1" ignore="true"/> + <field name="currentPrice" type="double" length="12" format="0.000000####"/> + <field name="padding" type="string" length="11" ignore="true"/> + <property name="source" value="camel-beanio"/> + </template> + + <template name="B1Record"> + <field name="sedol" type="string" length="7"/> + <field name="identifier" rid="true" literal="B1" ignore="true"/> + <field name="securityName" type="string" length="12"/> + <field name="padding" type="string" length="11" ignore="true"/> + <property name="source" value="camel-beanio"/> + </template> + + <stream name="securityData" format="fixedlength" strict="true"> + <group name="headerGroup" minOccurs="1" maxOccurs="1" order="1"> + <record name="headerA1" class="org.apache.camel.quarkus.component.beanio.it.model.Header" order="1" minLength="32" + maxLength="32" + minOccurs="1" maxOccurs="1"> + <field name="zeros" type="string" length="7" literal="0000000" ignore="true"/> + <field name="identifier" type="string" length="2" rid="true" literal="A1"/> + <field name="headerDate" type="date" length="6" format="ddMMyy"/> + <field name="recordType" type="string" length="17"/> + </record> + + <record name="headerB1" class="org.apache.camel.quarkus.component.beanio.it.model.Header" order="2" minLength="32" + maxLength="32" + minOccurs="1" maxOccurs="1"> + <field name="zeros" type="string" length="7" literal="0000000" ignore="true"/> + <field name="identifier" type="string" length="2" rid="true" literal="B1"/> + <field name="headerDate" type="date" length="6" format="ddMMyy"/> + <field name="recordType" type="string" length="17"/> + </record> + + <record name="headerEnd" class="org.apache.camel.quarkus.component.beanio.it.model.Separator" order="3" minLength="32" + maxLength="32" minOccurs="1" maxOccurs="1"> + <field name="value" rid="true" literal="HEADER END" default="HEADER END" required="true"/> + <field name="padding" length="22" ignore="true"/> + </record> + </group> + + <group name="section1" minOccurs="1" maxOccurs="1" order="2"> + <record name="A1" template="A1Record" + class="org.apache.camel.quarkus.component.beanio.it.model.A1Record" minOccurs="0" + maxOccurs="unbounded" minLength="32" maxLength="32"/> + <record name="B1" template="B1Record" + class="org.apache.camel.quarkus.component.beanio.it.model.B1Record" minOccurs="0" + maxOccurs="unbounded" minLength="32" maxLength="32"/> + <record name="endOfUk" class="org.apache.camel.quarkus.component.beanio.it.model.Separator" minOccurs="1" maxOccurs="1" + minLength="32" maxLength="32"> + <field name="value" rid="true" literal="END OF SECTION 1"/> + <field name="padding" length="16" ignore="true"/> + </record> + + </group> + + <group name="section2" minOccurs="1" maxOccurs="1" order="3"> + <record name="A1" template="A1Record" + class="org.apache.camel.quarkus.component.beanio.it.model.A1Record" minOccurs="0" + maxOccurs="unbounded" minLength="32" maxLength="32"/> + <record name="B1" template="B1Record" + class="org.apache.camel.quarkus.component.beanio.it.model.B1Record" minOccurs="0" + maxOccurs="unbounded" minLength="32" maxLength="32"/> + <record name="endOfFile" class="org.apache.camel.quarkus.component.beanio.it.model.Trailer" minOccurs="1" maxOccurs="1" + minLength="32" maxLength="32"> + <field name="endOfFile" rid="true" literal="END OF FILE" ignore="true"/> + <field name="spacer" literal=" " length="1" ignore="true"/> + <field name="numberOfRecords" type="integer" length="6" format="000000"/> + <field name="padding" length="14" ignore="true"/> + </record> + </group> + </stream> +</beanio> \ No newline at end of file diff --git a/integration-tests-jvm/beanio/src/main/resources/employee-mapping.xml b/integration-tests-jvm/beanio/src/main/resources/employee-mapping.xml new file mode 100644 index 0000000000..8773698947 --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/resources/employee-mapping.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<beanio xmlns="http://www.beanio.org/2012/03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd"> + <stream name="employeeCSV" format="csv"> + <record name="employee" class="org.apache.camel.quarkus.component.beanio.it.model.Employee"> + <field name="firstName"/> + <field name="lastName"/> + <field name="title"/> + <field name="salary"/> + <field name="hireDate" format="MMddyyyy"/> + </record> + </stream> + <stream name="employeeXML" format="xml"> + <record name="employee" class="org.apache.camel.quarkus.component.beanio.it.model.Employee"> + <field name="firstName"/> + <field name="lastName"/> + <field name="title"/> + <field name="salary"/> + <field name="hireDate" format="MMddyyyy"/> + </record> + </stream> + <stream name="employeeDelimited" format="delimited"> + <parser> + <property name="delimiter" value="|" /> + </parser> + <record name="employee" class="org.apache.camel.quarkus.component.beanio.it.model.Employee"> + <field name="firstName"/> + <field name="lastName"/> + <field name="title"/> + <field name="salary"/> + <field name="hireDate" format="MMddyyyy"/> + </record> + </stream> + <stream name="employeeFixedLength" format="fixedlength"> + <record name="employee" class="org.apache.camel.quarkus.component.beanio.it.model.Employee"> + <field name="firstName" length="10"/> + <field name="lastName" length="15"/> + <field name="title" length="15"/> + <field name="salary" length="10"/> + <field name="hireDate" format="MMddyyyy" length="8"/> + </record> + </stream> + <stream name="employeeAnnotated" format="csv"> + <record name="employeeAnnotated" class="org.apache.camel.quarkus.component.beanio.it.model.EmployeeAnnotated"/> + </stream> +</beanio> \ No newline at end of file diff --git a/integration-tests-jvm/beanio/src/main/resources/single-object-mapping.xml b/integration-tests-jvm/beanio/src/main/resources/single-object-mapping.xml new file mode 100644 index 0000000000..f158226945 --- /dev/null +++ b/integration-tests-jvm/beanio/src/main/resources/single-object-mapping.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<beanio xmlns="http://www.beanio.org/2012/03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd"> + <stream name="keyValueStream" format="fixedlength"> + <record name="entry" class="map" minOccurs="1"> + <field name="key" length="4" required="true" justify="left" /> + <field name="separator" length="1" required="true" justify="left" /> + <field name="value" required="true" length="unbounded" justify="left" /> + </record> + </stream> +</beanio> \ No newline at end of file diff --git a/integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java b/integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java index ae1ce7fcb6..e70c53bb2d 100644 --- a/integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java +++ b/integration-tests-jvm/beanio/src/test/java/org/apache/camel/quarkus/component/beanio/it/BeanioTest.java @@ -16,19 +16,312 @@ */ package org.apache.camel.quarkus.component.beanio.it; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import jakarta.json.bind.JsonbBuilder; +import org.apache.camel.quarkus.component.beanio.it.model.Employee; +import org.apache.camel.quarkus.component.beanio.it.model.EmployeeAnnotated; +import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.apache.camel.quarkus.component.beanio.it.BeanioResource.FORMATTER; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; @QuarkusTest class BeanioTest { + @ParameterizedTest + @ValueSource(strings = { "CSV", "DELIMITED", "FIXEDLENGTH", "XML", }) + void marshal(String type) throws Exception { + List<Employee> employees = new ArrayList<>(); + Employee one = new Employee(); + one.setFirstName("Joe"); + one.setLastName("Smith"); + one.setTitle("Developer"); + one.setSalary(75000); + one.setHireDate(FORMATTER.parse("2009-10-01")); + employees.add(one); + + Employee two = new Employee(); + two.setFirstName("Jane"); + two.setLastName("Doe"); + two.setTitle("Architect"); + two.setSalary(80000); + two.setHireDate(FORMATTER.parse("2008-01-15")); + employees.add(two); + + Employee three = new Employee(); + three.setFirstName("Jon"); + three.setLastName("Anderson"); + three.setTitle("Manager"); + three.setSalary(85000); + three.setHireDate(FORMATTER.parse("2007-03-18")); + employees.add(three); + + String expected = IOUtils.toString( + BeanioTest.class.getResourceAsStream("/employees-%s.txt".formatted(type.toLowerCase())), + StandardCharsets.UTF_8); + if (type.equals("XML")) { + // Clean up XML to match what is returned from beanio + expected = expected.replaceAll("(?s)<!--.*?-->", "").replaceAll(">[\\s\r\n]*<", "><"); + } + + String result = RestAssured.given() + .queryParam("type", type) + .contentType(ContentType.JSON) + .body(JsonbBuilder.create().toJson(employees)) + .post("/beanio/marshal") + .then() + .statusCode(200) + .extract() + .body() + .asString(); + + assertEquals(expected.trim(), result.trim()); + } + + @ParameterizedTest + @ValueSource(strings = { "CSV", "DELIMITED", "FIXEDLENGTH", "XML" }) + void unmarshal(String type) { + RestAssured.given() + .queryParam("type", type) + .contentType(ContentType.TEXT) + .body(BeanioTest.class.getResourceAsStream("/employees-%s.txt".formatted(type.toLowerCase()))) + .post("/beanio/unmarshal") + .then() + .statusCode(200) + .body( + "[0].firstName", is("Joe"), + "[0].lastName", is("Smith"), + "[0].title", is("Developer"), + "[0].salary", is(75000), + "[0].hireDate", is("2009-10-01"), + "[1].firstName", is("Jane"), + "[1].lastName", is("Doe"), + "[1].title", is("Architect"), + "[1].salary", is(80000), + "[1].hireDate", is("2008-01-15"), + "[2].firstName", is("Jon"), + "[2].lastName", is("Anderson"), + "[2].title", is("Manager"), + "[2].salary", is(85000), + "[2].hireDate", is("2007-03-18")); + } @Test - public void loadDataformatBeanio() { - /* A simple autogenerated test */ - RestAssured.get("/beanio/load/dataformat/beanio") + void marshalAnnotated() throws Exception { + List<EmployeeAnnotated> employees = new ArrayList<>(); + EmployeeAnnotated one = new EmployeeAnnotated(); + one.setFirstName("Joe"); + one.setLastName("Smith"); + one.setTitle("Developer"); + one.setSalary(75000); + one.setHireDate(FORMATTER.parse("2009-10-01")); + employees.add(one); + + EmployeeAnnotated two = new EmployeeAnnotated(); + two.setFirstName("Jane"); + two.setLastName("Doe"); + two.setTitle("Architect"); + two.setSalary(80000); + two.setHireDate(FORMATTER.parse("2008-01-15")); + employees.add(two); + + EmployeeAnnotated three = new EmployeeAnnotated(); + three.setFirstName("Jon"); + three.setLastName("Anderson"); + three.setTitle("Manager"); + three.setSalary(85000); + three.setHireDate(FORMATTER.parse("2007-03-18")); + employees.add(three); + + String expected = IOUtils.toString(BeanioTest.class.getResourceAsStream("/employees-csv.txt"), + StandardCharsets.UTF_8); + + String result = RestAssured.given() + .contentType(ContentType.JSON) + .body(JsonbBuilder.create().toJson(employees)) + .post("/beanio/marshal/annotated") + .then() + .statusCode(200) + .extract() + .body() + .asString(); + + assertEquals(expected.trim(), result.trim()); + } + + @Test + void unmarshalAnnotated() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body(BeanioTest.class.getResourceAsStream("/employees-csv.txt")) + .post("/beanio/unmarshal/annotated") .then() - .statusCode(200); + .statusCode(200) + .body( + "[0].firstName", is("Joe"), + "[0].lastName", is("Smith"), + "[0].title", is("Developer"), + "[0].salary", is(75000), + "[0].hireDate", is("2009-10-01"), + "[1].firstName", is("Jane"), + "[1].lastName", is("Doe"), + "[1].title", is("Architect"), + "[1].salary", is(80000), + "[1].hireDate", is("2008-01-15"), + "[2].firstName", is("Jon"), + "[2].lastName", is("Anderson"), + "[2].title", is("Manager"), + "[2].salary", is(85000), + "[2].hireDate", is("2007-03-18")); } + @Test + void marshalSingleObject() { + Map<String, String> data = Map.of( + "separator", ":", + "value", "Content starts from here\nthen continues\nand ends here.", + "key", "1234"); + + String expected = data.get("key") + data.get("separator") + data.get("value"); + String result = RestAssured.given() + .contentType(ContentType.JSON) + .body(JsonbBuilder.create().toJson(data)) + .post("/beanio/marshal/single/object") + .then() + .statusCode(200) + .extract() + .body() + .asString(); + + assertEquals(expected, result.trim()); + } + + @Test + void unmarshalSingleObject() { + String data = "1234:Content starts from here\nthen continues\nand ends here."; + RestAssured.given() + .contentType(ContentType.TEXT) + .body(data) + .post("/beanio/unmarshal/single/object") + .then() + .statusCode(200) + .body( + "separator", is(":"), + "value", is(data.split(":")[1]), + "key", is("1234")); + + } + + @Test + void unmarshalWithErrorHandler() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body(BeanioTest.class.getResourceAsStream("/employees-with-error.txt")) + .post("/beanio/unmarshal/with/error/handler") + .then() + .statusCode(200) + .body( + "[0].firstName", is("Joe"), + "[0].lastName", is("Smith"), + "[0].title", is("Developer"), + "[0].salary", is(75000), + "[0].hireDate", is("2009-10-01"), + "[1].firstName", is("Jane"), + "[1].lastName", is("Doe"), + "[1].title", is("Architect"), + "[1].salary", is(80000), + "[1].hireDate", is("2008-01-15"), + "[2].message", is("Invalid 'employee' record at line 3"), + "[2].record", is("employee")); + } + + @Test + void marshalComplexObject() throws Exception { + String expected = IOUtils.toString(BeanioTest.class.getResourceAsStream("/complex-data.txt"), StandardCharsets.UTF_8); + String result = RestAssured.given() + .post("/beanio/marshal/complex/object") + .then() + .statusCode(200) + .extract() + .body() + .asString(); + assertEquals(expected, result); + } + + @Test + void unmarshalComplexObject() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body(BeanioTest.class.getResourceAsStream("/complex-data.txt")) + .post("/beanio/unmarshal/complex/object") + .then() + .statusCode(200) + .body( + "[0].identifier", is("A1"), + "[0].recordType", is("PRICE"), + "[0].date", is("2008-08-03"), + "[1].identifier", is("B1"), + "[1].recordType", is("SECURITY"), + "[1].date", is("2008-08-03"), + "[2].value", is("HEADER END"), + "[3].price", is("12345.68"), + "[3].sedol", is("0001917"), + "[3].source", is("camel-beanio"), + "[4].price", is("59303290.02"), + "[4].sedol", is("0002374"), + "[4].source", is("camel-beanio"), + "[5].securityName", is("SECURITY ONE"), + "[5].sedol", is("0015219"), + "[5].source", is("camel-beanio"), + "[6].value", is("END OF SECTION 1"), + "[7].price", is("0.00"), + "[7].sedol", is("0076647"), + "[7].source", is("camel-beanio"), + "[8].price", is("999999999999.00"), + "[8].sedol", is("0135515"), + "[8].source", is("camel-beanio"), + "[9].securityName", is("SECURITY TWO"), + "[9].sedol", is("2000815"), + "[9].source", is("camel-beanio"), + "[10].securityName", is("SECURITY THR"), + "[10].sedol", is("2207122"), + "[10].source", is("camel-beanio"), + "[11].numberOfRecords", is(7)); + } + + @Test + void splitter() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body(BeanioTest.class.getResourceAsStream("/employees-csv.txt")) + .post("/beanio/split") + .then() + .statusCode(200) + .body( + "[0].firstName", is("Joe"), + "[0].lastName", is("Smith"), + "[0].title", is("Developer"), + "[0].salary", is(75000), + "[0].hireDate", is("2009-10-01"), + "[1].firstName", is("Jane"), + "[1].lastName", is("Doe"), + "[1].title", is("Architect"), + "[1].salary", is(80000), + "[1].hireDate", is("2008-01-15"), + "[2].firstName", is("Jon"), + "[2].lastName", is("Anderson"), + "[2].title", is("Manager"), + "[2].salary", is(85000), + "[2].hireDate", is("2007-03-18")); + } } diff --git a/integration-tests-jvm/beanio/src/test/resources/complex-data.txt b/integration-tests-jvm/beanio/src/test/resources/complex-data.txt new file mode 100644 index 0000000000..0da5c2edb4 --- /dev/null +++ b/integration-tests-jvm/beanio/src/test/resources/complex-data.txt @@ -0,0 +1,12 @@ +0000000A1030808PRICE +0000000B1030808SECURITY +HEADER END +0001917A112345.678900 +0002374A159303290.020 +0015219B1SECURITY ONE +END OF SECTION 1 +0076647A10.0000000001 +0135515A1999999999999 +2000815B1SECURITY TWO +2207122B1SECURITY THR +END OF FILE 000007 diff --git a/integration-tests-jvm/beanio/src/test/resources/employees-csv.txt b/integration-tests-jvm/beanio/src/test/resources/employees-csv.txt new file mode 100644 index 0000000000..6c05f5ec17 --- /dev/null +++ b/integration-tests-jvm/beanio/src/test/resources/employees-csv.txt @@ -0,0 +1,3 @@ +Joe,Smith,Developer,75000,10012009 +Jane,Doe,Architect,80000,01152008 +Jon,Anderson,Manager,85000,03182007 \ No newline at end of file diff --git a/integration-tests-jvm/beanio/src/test/resources/employees-delimited.txt b/integration-tests-jvm/beanio/src/test/resources/employees-delimited.txt new file mode 100644 index 0000000000..6ef9eed965 --- /dev/null +++ b/integration-tests-jvm/beanio/src/test/resources/employees-delimited.txt @@ -0,0 +1,3 @@ +Joe|Smith|Developer|75000|10012009 +Jane|Doe|Architect|80000|01152008 +Jon|Anderson|Manager|85000|03182007 diff --git a/integration-tests-jvm/beanio/src/test/resources/employees-fixedlength.txt b/integration-tests-jvm/beanio/src/test/resources/employees-fixedlength.txt new file mode 100644 index 0000000000..8ea0749e80 --- /dev/null +++ b/integration-tests-jvm/beanio/src/test/resources/employees-fixedlength.txt @@ -0,0 +1,3 @@ +Joe Smith Developer 75000 10012009 +Jane Doe Architect 80000 01152008 +Jon Anderson Manager 85000 03182007 \ No newline at end of file diff --git a/integration-tests-jvm/beanio/src/test/resources/employees-with-error.txt b/integration-tests-jvm/beanio/src/test/resources/employees-with-error.txt new file mode 100644 index 0000000000..d345b993ca --- /dev/null +++ b/integration-tests-jvm/beanio/src/test/resources/employees-with-error.txt @@ -0,0 +1,3 @@ +Joe,Smith,Developer,75000,10012009 +Jane,Doe,Architect,80000,01152008 +Jon,Anderson,Manager,XXXX,03182007 \ No newline at end of file diff --git a/integration-tests-jvm/beanio/src/test/resources/employees-xml.txt b/integration-tests-jvm/beanio/src/test/resources/employees-xml.txt new file mode 100644 index 0000000000..a04e44478e --- /dev/null +++ b/integration-tests-jvm/beanio/src/test/resources/employees-xml.txt @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<employeeXML> + <employee> + <firstName>Joe</firstName> + <lastName>Smith</lastName> + <title>Developer</title> + <salary>75000</salary> + <hireDate>10012009</hireDate> + </employee> + <employee> + <firstName>Jane</firstName> + <lastName>Doe</lastName> + <title>Architect</title> + <salary>80000</salary> + <hireDate>01152008</hireDate> + </employee> + <employee> + <firstName>Jon</firstName> + <lastName>Anderson</lastName> + <title>Manager</title> + <salary>85000</salary> + <hireDate>03182007</hireDate> + </employee> +</employeeXML>
