diff --git a/History.md b/History.md index 04fc09cb..f81e1a42 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,4 @@ - +- Jacksonability: Invoice can now be Stringified to / restored from a JSON using Jackson - Fixed an error validation UBL files - unknown root elements will now throw type 3 errors - added some tests diff --git a/doc/development_documentation.md b/doc/development_documentation.md index 1e9c037d..aaf4bd31 100644 --- a/doc/development_documentation.md +++ b/doc/development_documentation.md @@ -5,6 +5,7 @@ To check if the necessary tools are there, the build is in a stable state and works on your platform, e.g. download and extract https://github.com/ZUGFeRD/mustangproject/archive/master.zip and run ./mvnw clean package +Mvnw is a maven wrapper which will download maven.Maven is the dependency management tool which will download all libraries, their dependencies, and build the whole thing. Mvnw is a maven wrapper which will download maven.Maven is the dependency management tool which will download all libraries, their dependencies, and build the whole thing. You will need a Java JDK, e.g. https://www.azul.com/downloads/zulu-community/?architecture=x86-64-bit&package=jdk @@ -159,7 +160,11 @@ If you added functionality which you need to test in another project before a ne install the jar you just generated in your target branch in your local maven cache so it gets picked *instead* of the maybe not yet even existing new release version: -`mvn install:install-file -Dfile=mustang-1.7.6-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.7.6 -Dpackaging=jar -DgeneratePom=true` +``` +cd validator/target +mvn install:install-file -Dfile=validator-2.3.2-SNAPSHOT-shaded.jar -DgroupId=org.mustangproject -DartifactId=validator -Dversion=2.3.2 -Dpackaging=jar -DgeneratePom=true +``` +This will also work in Gradle given you have the `mavenLocal()` repository activated. ## Release diff --git a/library/pom.xml b/library/pom.xml index 2f02c1a4..5d7be630 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -57,7 +57,13 @@ net.sf.saxon Saxon-HE 9.9.0-1 + + + com.fasterxml.jackson.core + jackson-databind + 2.13.0 + javax.activation activation diff --git a/library/src/main/java/org/mustangproject/Contact.java b/library/src/main/java/org/mustangproject/Contact.java index 455b66bd..514c18f2 100644 --- a/library/src/main/java/org/mustangproject/Contact.java +++ b/library/src/main/java/org/mustangproject/Contact.java @@ -1,5 +1,6 @@ package org.mustangproject; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -9,6 +10,7 @@ import org.w3c.dom.NodeList; * for the organisation/company itsel please * @see TradeParty */ +@JsonIgnoreProperties(ignoreUnknown = true) public class Contact implements IZUGFeRDExportableContact { protected String name, phone, email, zip, street, location, country; @@ -27,6 +29,13 @@ public class Contact implements IZUGFeRDExportableContact { this.email = email; } + /*** + * empty constructor. + * as always, not recommended, for jackson... + */ + public Contact() { + } + /*** * complete specification of a named contact with a different address * @param name full name diff --git a/library/src/main/java/org/mustangproject/Invoice.java b/library/src/main/java/org/mustangproject/Invoice.java index a99752e4..442aebeb 100644 --- a/library/src/main/java/org/mustangproject/Invoice.java +++ b/library/src/main/java/org/mustangproject/Invoice.java @@ -20,6 +20,8 @@ */ package org.mustangproject; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.mustangproject.ZUGFeRD.*; import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants; @@ -31,15 +33,17 @@ import java.util.Date; * An invoice, with fluent setters * @see IExportableTransaction if you want to implement an interface instead */ +@JsonIgnoreProperties(ignoreUnknown = true) public class Invoice implements IExportableTransaction { protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, invoiceReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null; protected Date issueDate = null, dueDate = null, deliveryDate = null; protected BigDecimal totalPrepaidAmount = null; protected TradeParty sender = null, recipient = null, deliveryAddress = null; + @JsonDeserialize(contentAs=Item.class) protected ArrayList ZFItems = null; protected ArrayList notes = null; - private String sellerOrderReferencedDocumentID; + protected String sellerOrderReferencedDocumentID; protected String contractReferencedDocument = null; protected ArrayList xmlEmbeddedFiles=null; @@ -49,12 +53,9 @@ public class Invoice implements IExportableTransaction { protected ArrayList Allowances = new ArrayList<>(), Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>(); protected IZUGFeRDPaymentTerms paymentTerms = null; - private Date invoiceReferencedIssueDate; - private String specifiedProcuringProjectID = null; - - - - private String specifiedProcuringProjectName = null; + protected Date invoiceReferencedIssueDate; + protected String specifiedProcuringProjectID = null; + protected String specifiedProcuringProjectName = null; public Invoice() { ZFItems = new ArrayList<>(); @@ -551,6 +552,10 @@ public class Invoice implements IExportableTransaction { return ZFItems.toArray(new IZUGFeRDExportableItem[0]); } + public void setZFItems(ArrayList ims) { + ZFItems=ims; + } + /** * required * adds invoice "lines" :-) diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index 2d8de5b9..704ee36d 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -1,5 +1,6 @@ package org.mustangproject; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.mustangproject.ZUGFeRD.IReferencedDocument; import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem; @@ -11,6 +12,8 @@ import java.util.Date; /*** * describes any invoice line */ + +@JsonIgnoreProperties(ignoreUnknown = true) public class Item implements IZUGFeRDExportableItem { protected BigDecimal price, quantity, tax, grossPrice, lineTotalAmount; protected Date detailedDeliveryPeriodFrom=null, detailedDeliveryPeriodTo=null; @@ -35,6 +38,13 @@ public class Item implements IZUGFeRDExportableItem { } + /*** + * empty constructor + * do not use, but might be used e.g. by jackson + * */ + public Item() { + } + public Item addReferencedLineID(String s) { referencedLineID=s; return this; diff --git a/library/src/main/java/org/mustangproject/Product.java b/library/src/main/java/org/mustangproject/Product.java index 29d15c78..ab45418b 100644 --- a/library/src/main/java/org/mustangproject/Product.java +++ b/library/src/main/java/org/mustangproject/Product.java @@ -1,5 +1,6 @@ package org.mustangproject; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct; import java.math.BigDecimal; @@ -7,6 +8,7 @@ import java.math.BigDecimal; /*** * describes a product, good or service used in an invoice item line */ +@JsonIgnoreProperties(ignoreUnknown = true) public class Product implements IZUGFeRDExportableProduct { protected String unit, name, description, sellerAssignedID, buyerAssignedID; protected BigDecimal VATPercent; @@ -28,6 +30,15 @@ public class Product implements IZUGFeRDExportableProduct { } + /*** + * empty constructor + * just for jackson etc + */ + public Product() { + + } + + public String getSellerAssignedID() { return sellerAssignedID; } diff --git a/library/src/main/java/org/mustangproject/TradeParty.java b/library/src/main/java/org/mustangproject/TradeParty.java index ffac8008..b406abaa 100644 --- a/library/src/main/java/org/mustangproject/TradeParty.java +++ b/library/src/main/java/org/mustangproject/TradeParty.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty; import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlement; @@ -15,6 +16,7 @@ import org.w3c.dom.NodeList; /*** * A organisation, i.e. usually a company */ +@JsonIgnoreProperties(ignoreUnknown = true) public class TradeParty implements IZUGFeRDExportableTradeParty { protected String name, zip, street, location, country; @@ -25,6 +27,15 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { protected List debitDetails = new ArrayList<>(); protected Contact contact = null; + /** + * Default constructor. + * Probably a bad idea but might be needed by jackson or similar + */ + public TradeParty() { + + } + + /*** * * @param name of the company @@ -118,13 +129,11 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { if (taxChilds.item(taxChildIndex).getLocalName() != null) { if ((taxChilds.item(taxChildIndex).getLocalName().equals("ID"))) { - if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID")!=null) { - if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("VA")) - { + if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) { + if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("VA")) { setVATID(taxChilds.item(taxChildIndex).getFirstChild().getNodeValue()); } - if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("FC")) - { + if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("FC")) { setTaxID(taxChilds.item(taxChildIndex).getFirstChild().getNodeValue()); } } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java index 65318300..9730df2c 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java @@ -26,11 +26,14 @@ package org.mustangproject.ZUGFeRD; * @author jstaerk * */ +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.mustangproject.Item; + import java.math.BigDecimal; import java.util.Date; +@JsonDeserialize(as = Item.class) public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{ - IZUGFeRDExportableProduct getProduct(); /** diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java new file mode 100644 index 00000000..0e9ea12d --- /dev/null +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java @@ -0,0 +1,53 @@ + +/** + * ********************************************************************* + *

+ * Copyright 2019 Jochen Staerk + *

+ * Use is subject to license terms. + *

+ * Licensed 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.mustangproject.ZUGFeRD; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import junit.framework.TestCase; +import org.assertj.core.util.Lists; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; +import org.mustangproject.*; + +import java.math.BigDecimal; +import java.util.Date; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class DeSerializationTest extends TestCase { + public void testJackson() throws JsonProcessingException { + + ObjectMapper mapper = new ObjectMapper(); + Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty("some org", "teststr", "55232", "teststadt", "DE").addTaxID("taxID")).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber("0185").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal("1"), new BigDecimal(1.0))); + String jsonArray = mapper.writeValueAsString(i); + + // [{"stringValue":"a","intValue":1,"booleanValue":true}, + // {"stringValue":"bc","intValue":3,"booleanValue":false}] + + Invoice fromJSON = mapper.readValue(jsonArray, Invoice.class); + assertEquals(fromJSON.getNumber(), i.getNumber()); + assertEquals(fromJSON.getZFItems().length, i.getZFItems().length); + + } +}