From 764d433c5161d278808695436ff7e095b31b405b Mon Sep 17 00:00:00 2001 From: eberhardtj <30794167+eberhardtj@users.noreply.github.com> Date: Wed, 4 Apr 2018 10:25:15 +0200 Subject: [PATCH 1/4] Add marshalling to xml as a alternative for stream to xml --- .../org/metafacture/xml/MarshalEncoder.java | 223 ++++++++++++++++++ .../metafacture/xml/MarshalXmlHandler.java | 120 ++++++++++ .../main/resources/flux-commands.properties | 2 + .../metafacture/xml/MarshalEncoderTest.java | 160 +++++++++++++ .../xml/MarshalXmlHandlerTest.java | 113 +++++++++ 5 files changed, 618 insertions(+) create mode 100644 metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java create mode 100644 metafacture-xml/src/main/java/org/metafacture/xml/MarshalXmlHandler.java create mode 100644 metafacture-xml/src/test/java/org/metafacture/xml/MarshalEncoderTest.java create mode 100644 metafacture-xml/src/test/java/org/metafacture/xml/MarshalXmlHandlerTest.java diff --git a/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java b/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java new file mode 100644 index 000000000..125cb1d9c --- /dev/null +++ b/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java @@ -0,0 +1,223 @@ +/* + * Copyright 2018 Deutsche Nationalbibliothek + * + * 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.metafacture.xml; + +import org.metafacture.framework.FluxCommand; +import org.metafacture.framework.ObjectReceiver; +import org.metafacture.framework.StreamReceiver; +import org.metafacture.framework.annotations.Description; +import org.metafacture.framework.annotations.In; +import org.metafacture.framework.annotations.Out; +import org.metafacture.framework.helpers.DefaultStreamPipe; + +@Description("MarshalEncoder a stream to XML.") +@In(StreamReceiver.class) +@Out(String.class) +@FluxCommand("marshal-to-xml") +public class MarshalEncoder extends DefaultStreamPipe> +{ + final private String xmlDeclaration = ""; + final private String spacer = " "; + + private boolean initStream; + private boolean prettyPrint; + private int indentation; + private StringBuilder stringBuilder; + + private boolean omitDeclaration = false; + private boolean omitRoot = false; + + public MarshalEncoder() + { + this.indentation = 0; + this.prettyPrint = true; + this.initStream = true; + } + + public void setPrettyPrint(boolean prettyPrint) + { + this.prettyPrint = prettyPrint; + } + + public void setOmitDeclaration(boolean omitDeclaration) + { + this.omitDeclaration = omitDeclaration; + } + + public void setOmitRoot(boolean omitRoot) + { + this.omitRoot = omitRoot; + } + + @Override + public void startRecord(final String identifier) + { + if (initStream) + { + if (!omitDeclaration) + { + getReceiver().process(xmlDeclaration); + } + if (!omitRoot) + { + getReceiver().process(""); + } + initStream = false; + } + + String elem = ""; + if (prettyPrint) + { + indentation++; + getReceiver().process(spacer + elem); + } + else + { + stringBuilder = new StringBuilder(); + stringBuilder.append(elem); + } + } + + @Override + public void startEntity(final String name) + { + String elem = ""; + if (prettyPrint) + { + indentation++; + getReceiver().process(separators(indentation, spacer) + elem); + } + else + { + stringBuilder.append(elem); + } + } + + @Override + public void literal(final String name, final String value) + { + String elem = "" + escape(value) + ""; + if (prettyPrint) + { + getReceiver().process(separators(indentation+1, spacer) + elem); + } + else + { + stringBuilder.append(elem); + } + } + + @Override + public void endEntity() + { + String elem = ""; + if (prettyPrint) + { + getReceiver().process(separators(indentation, spacer) + elem); + indentation--; + } + else + { + stringBuilder.append(elem); + } + } + + @Override + public void endRecord() + { + String elem = ""; + if (prettyPrint) + { + getReceiver().process(spacer + ""); + indentation--; + } + else + { + stringBuilder.append(elem); + getReceiver().process(stringBuilder.toString().trim()); + } + } + + @Override + public void onCloseStream() + { + if (!omitRoot) + { + getReceiver().process(""); + } + } + + @Override + public void onResetStream() + { + this.indentation = 0; + this.initStream = true; + } + + private String separators(int amount, String separator) + { + StringBuilder sb = new StringBuilder(separator); + for (int i = 0; i < amount - 1; i++) + { + sb.append(separator); + } + return sb.toString(); + } + + private String escape(final String s) + { + if (s == null || s.isEmpty()) + { + return ""; + } + + StringBuilder result = new StringBuilder(); + final int len = s.length(); + for (int i = 0; i < len; ++i) { + final char c = s.charAt(i); + final String entityName; + switch (c) { + case '&': + entityName = "amp"; + break; + case '<': + entityName = "lt"; + break; + case '>': + entityName = "gt"; + break; + case '\'': + entityName = "apos"; + break; + case '"': + entityName = "quot"; + break; + default: + entityName = null; + break; + } + + if (entityName == null) { + result.append(c); + } else { + result.append('&'); + result.append(entityName); + result.append(';'); + } + } + return result.toString().trim(); + } +} diff --git a/metafacture-xml/src/main/java/org/metafacture/xml/MarshalXmlHandler.java b/metafacture-xml/src/main/java/org/metafacture/xml/MarshalXmlHandler.java new file mode 100644 index 000000000..27817a66e --- /dev/null +++ b/metafacture-xml/src/main/java/org/metafacture/xml/MarshalXmlHandler.java @@ -0,0 +1,120 @@ +/* + * Copyright 2018 Deutsche Nationalbibliothek + * + * 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.metafacture.xml; + +import org.metafacture.framework.FluxCommand; +import org.metafacture.framework.MetafactureException; +import org.metafacture.framework.StreamReceiver; +import org.metafacture.framework.XmlReceiver; +import org.metafacture.framework.annotations.Description; +import org.metafacture.framework.annotations.In; +import org.metafacture.framework.annotations.Out; +import org.metafacture.framework.helpers.DefaultXmlPipe; +import org.xml.sax.Attributes; + +@Description("Unmarshalling a XML stream.") +@In(XmlReceiver.class) +@Out(StreamReceiver.class) +@FluxCommand("handle-marshal-xml") +public class MarshalXmlHandler extends DefaultXmlPipe +{ + + final private String ID = "id"; + final private String NAME = "name"; + + private int streamTagCount; + private String currentTag; + private String currentLiteralName; + private StringBuilder stringBuilder; + + public MarshalXmlHandler() + { + streamTagCount = 0; + stringBuilder = new StringBuilder(); + } + + @Override + public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) + { + currentTag = localName.toUpperCase(); + switch (currentTag) + { + case "STREAM": + if (streamTagCount > 0) + { + throw new MetafactureException("Root tag 'stream' opened a second time."); + } + streamTagCount += 1; + case "RECORD": + String identifier = attributes.getValue(ID); + getReceiver().startRecord(identifier); + break; + case "ENTITY": + String name = attributes.getValue(NAME); + getReceiver().startEntity(name); + break; + case "LITERAL": + currentLiteralName = attributes.getValue(NAME); + break; + default: + String message = "Unknown tag '%s'. Expected 'stream', 'record', 'entity' or 'literal'."; + throw new MetafactureException(String.format(message, currentTag)); + } + } + + @Override + public void characters(final char[] chars, final int start, final int length) + { + if (currentTag.equals("LITERAL")) + { + this.stringBuilder.append(chars, start, length); + } + } + + @Override + public void endElement(final String uri, final String localName, final String qName) + { + currentTag = localName.toUpperCase(); + switch (currentTag) + { + case "STREAM": + streamTagCount -= 1; + if (streamTagCount != 0) + { + throw new MetafactureException("Root tag 'stream' closed a second time."); + } + else + { + getReceiver().closeStream(); + } + break; + case "RECORD": + getReceiver().endRecord(); + break; + case "ENTITY": + getReceiver().endEntity(); + break; + case "LITERAL": + String currentLiteralValue = stringBuilder.toString().trim(); + getReceiver().literal(currentLiteralName, currentLiteralValue); + stringBuilder = new StringBuilder(); + break; + default: + String message = "Unknown tag '%s'. Expected 'stream', 'record', 'entity' or 'literal'."; + throw new MetafactureException(String.format(message, currentTag)); + } + } +} diff --git a/metafacture-xml/src/main/resources/flux-commands.properties b/metafacture-xml/src/main/resources/flux-commands.properties index c69356ce0..39821eaac 100644 --- a/metafacture-xml/src/main/resources/flux-commands.properties +++ b/metafacture-xml/src/main/resources/flux-commands.properties @@ -15,6 +15,8 @@ # handle-cg-xml org.metafacture.xml.CGXmlHandler handle-generic-xml org.metafacture.xml.GenericXmlHandler +handle-marshal-xml org.metafacture.xml.MarshalXmlHandler +marshal-to-xml org.metafacture.xml.MarshalEncoder stream-to-xml org.metafacture.xml.SimpleXmlEncoder decode-xml org.metafacture.xml.XmlDecoder split-xml-elements org.metafacture.xml.XmlElementSplitter diff --git a/metafacture-xml/src/test/java/org/metafacture/xml/MarshalEncoderTest.java b/metafacture-xml/src/test/java/org/metafacture/xml/MarshalEncoderTest.java new file mode 100644 index 000000000..8ea3f9ecc --- /dev/null +++ b/metafacture-xml/src/test/java/org/metafacture/xml/MarshalEncoderTest.java @@ -0,0 +1,160 @@ +/* + * Copyright 2018 Deutsche Nationalbibliothek + * + * 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.metafacture.xml; + +import org.junit.Before; +import org.junit.Test; +import org.metafacture.framework.ObjectReceiver; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.verify; +import static org.mockito.internal.verification.VerificationModeFactory.times; + +public class MarshalEncoderTest +{ + private MarshalEncoder encoder; + + @Mock + private ObjectReceiver receiver; + + @Before + public void setUp() + { + MockitoAnnotations.initMocks(this); + encoder = new MarshalEncoder(); + encoder.setReceiver(receiver); + } + + @Test + public void marshalling() + { + encoder.startRecord("1"); + encoder.literal("id", "1"); + encoder.startEntity("<>"); + encoder.literal("name", "joe"); + encoder.endEntity(); + encoder.endRecord(); + + encoder.startRecord("1"); + encoder.literal("id", "1"); + encoder.startEntity("<>"); + encoder.literal("name", "joe"); + encoder.endEntity(); + encoder.endRecord(); + + encoder.closeStream(); + + final InOrder ordered = inOrder(receiver); + ordered.verify(receiver).process(""); + ordered.verify(receiver).process(""); + ordered.verify(receiver).process(" "); + ordered.verify(receiver).process(" 1"); + ordered.verify(receiver).process(" "); + ordered.verify(receiver).process(" joe"); + ordered.verify(receiver).process(" "); + ordered.verify(receiver).process(" "); + ordered.verify(receiver).process(" "); + ordered.verify(receiver).process(" 1"); + ordered.verify(receiver).process(" "); + ordered.verify(receiver).process(" joe"); + ordered.verify(receiver).process(" "); + ordered.verify(receiver).process(" "); + ordered.verify(receiver).process(""); + } + + @Test + public void marshallingWithoutPrettyPrinting() + { + encoder.setPrettyPrint(false); + + encoder.startRecord("1"); + encoder.literal("id", "1"); + encoder.startEntity("names"); + encoder.literal("name", "joe"); + encoder.endEntity(); + encoder.endRecord(); + + encoder.startRecord("1"); + encoder.literal("id", "1"); + encoder.startEntity("names"); + encoder.literal("name", "joe"); + encoder.endEntity(); + encoder.endRecord(); + encoder.closeStream(); + + final InOrder ordered = inOrder(receiver); + ordered.verify(receiver).process(""); + ordered.verify(receiver).process(""); + ordered.verify(receiver, times(2)).process( + "" + + "1" + + "joe" + + "" + ); + ordered.verify(receiver).process(""); + } + + @Test + public void marshallingWithNullValue() + { + encoder.setPrettyPrint(false); + + encoder.startRecord("1"); + encoder.literal("value", null); + encoder.endRecord(); + encoder.closeStream(); + + final InOrder ordered = inOrder(receiver); + ordered.verify(receiver).process(""); + ordered.verify(receiver).process(""); + ordered.verify(receiver).process(""); + ordered.verify(receiver).process(""); + } + + @Test + public void omitDeclaration() + { + encoder.setPrettyPrint(false); + encoder.setOmitDeclaration(true); + + encoder.startRecord("1"); + encoder.literal("value", null); + encoder.endRecord(); + encoder.closeStream(); + + final InOrder ordered = inOrder(receiver); + ordered.verify(receiver).process(""); + ordered.verify(receiver).process(""); + ordered.verify(receiver).process(""); + } + + @Test + public void omitRoot() + { + encoder.setPrettyPrint(false); + encoder.setOmitDeclaration(true); + encoder.setOmitRoot(true); + + encoder.startRecord("1"); + encoder.literal("value", null); + encoder.endRecord(); + encoder.closeStream(); + + verify(receiver).process(""); + } +} diff --git a/metafacture-xml/src/test/java/org/metafacture/xml/MarshalXmlHandlerTest.java b/metafacture-xml/src/test/java/org/metafacture/xml/MarshalXmlHandlerTest.java new file mode 100644 index 000000000..81bcb8e7e --- /dev/null +++ b/metafacture-xml/src/test/java/org/metafacture/xml/MarshalXmlHandlerTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2018 Deutsche Nationalbibliothek + * + * 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.metafacture.xml; + +import org.junit.Before; +import org.junit.Test; +import org.metafacture.framework.MetafactureException; +import org.metafacture.framework.StreamReceiver; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.xml.sax.helpers.AttributesImpl; +import static org.mockito.Mockito.inOrder; + +public class MarshalXmlHandlerTest +{ + + private MarshalXmlHandler handler; + + @Mock + private StreamReceiver receiver; + + @Before + public void setUp() + { + MockitoAnnotations.initMocks(this); + handler = new MarshalXmlHandler(); + handler.setReceiver(receiver); + } + + @Test(expected = MetafactureException.class) + public void complainAboutMissingRootTagNamedStream() + { + handler.startElement("", "notStream", "notStream", new AttributesImpl()); + } + + @Test(expected = MetafactureException.class) + public void complainAboutASecondlyOpenedRootTag() + { + handler.startElement("", "stream", "stream", new AttributesImpl()); + handler.startElement("", "stream", "stream", new AttributesImpl()); + } + + @Test(expected = MetafactureException.class) + public void complainAboutAboutASecondlyClosedRootTag() + { + handler.endElement("", "stream", "stream"); + handler.endElement("", "stream", "stream"); + } + + @Test + public void readXmlStream() + { + // + handler.startElement("", "stream", "stream", new AttributesImpl()); + + // + final AttributesImpl recordAttributes = new AttributesImpl(); + recordAttributes.addAttribute("", "id", "id", "ID", "1"); + handler.startElement("", "record", "record", recordAttributes); + + // 1 + final AttributesImpl literal1Attributes = new AttributesImpl(); + literal1Attributes.addAttribute("", "name", "name", "CDATA", "id"); + handler.startElement("", "literal", "literal", literal1Attributes); + handler.characters("1".toCharArray(), 0, 1); + handler.endElement("", "literal", "literal"); + + // + final AttributesImpl entityAttributes = new AttributesImpl(); + entityAttributes.addAttribute("", "name", "name", "CDATA", "names"); + handler.startElement("", "entity", "entity", entityAttributes); + + // "joe" + final AttributesImpl literal2Attributes = new AttributesImpl(); + literal2Attributes.addAttribute("", "name", "name", "CDATA", "name"); + handler.startElement("", "literal", "literal", literal2Attributes); + handler.characters("\"joe\"".toCharArray(), 0, "\"joe\"".length()); + handler.endElement("", "literal", "literal"); + + // + handler.endElement("", "entity", "entity"); + + // + handler.endElement("", "record", "record"); + + // + handler.endElement("", "stream", "stream"); + + final InOrder ordered = inOrder(receiver); + ordered.verify(receiver).startRecord("1"); + ordered.verify(receiver).literal("id", "1"); + ordered.verify(receiver).startEntity("names"); + ordered.verify(receiver).literal("name", "\"joe\""); + ordered.verify(receiver).endEntity(); + ordered.verify(receiver).endRecord(); + ordered.verify(receiver).closeStream(); + ordered.verifyNoMoreInteractions(); + } +} From 73aba05d2ebe489a8653a1bfcf960525913e6022 Mon Sep 17 00:00:00 2001 From: eberhardtj <30794167+eberhardtj@users.noreply.github.com> Date: Fri, 18 May 2018 08:47:13 +0200 Subject: [PATCH 2/4] Add doc string Adds a doc string that contains the escaped control characters. --- .../src/main/java/org/metafacture/xml/MarshalEncoder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java b/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java index 125cb1d9c..33fe983f5 100644 --- a/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java +++ b/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java @@ -177,6 +177,9 @@ private String separators(int amount, String separator) return sb.toString(); } + /** + * Escapes the following control characters: {@code <}, {@code >}, {@code "}, {@code '}, and {@code &} . + */ private String escape(final String s) { if (s == null || s.isEmpty()) From 6d119731ff2a634c7a1ffead6d2583f025607e90 Mon Sep 17 00:00:00 2001 From: eberhardtj <30794167+eberhardtj@users.noreply.github.com> Date: Fri, 18 May 2018 09:12:48 +0200 Subject: [PATCH 3/4] Rename from marshal to serialize Renames the class from marshal to serialize. The class copies the structure of the internal stream to a primitive form, which is equal to the semantic meaning of serialization. --- .../{MarshalEncoder.java => SerializeEncoder.java} | 8 ++++---- ...shalXmlHandler.java => SerializeXmlHandler.java} | 8 ++++---- .../src/main/resources/flux-commands.properties | 4 ++-- ...alEncoderTest.java => SerializeEncoderTest.java} | 13 +++++++------ ...andlerTest.java => SerializeXmlHandlerTest.java} | 6 +++--- 5 files changed, 20 insertions(+), 19 deletions(-) rename metafacture-xml/src/main/java/org/metafacture/xml/{MarshalEncoder.java => SerializeEncoder.java} (96%) rename metafacture-xml/src/main/java/org/metafacture/xml/{MarshalXmlHandler.java => SerializeXmlHandler.java} (95%) rename metafacture-xml/src/test/java/org/metafacture/xml/{MarshalEncoderTest.java => SerializeEncoderTest.java} (95%) rename metafacture-xml/src/test/java/org/metafacture/xml/{MarshalXmlHandlerTest.java => SerializeXmlHandlerTest.java} (96%) diff --git a/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java b/metafacture-xml/src/main/java/org/metafacture/xml/SerializeEncoder.java similarity index 96% rename from metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java rename to metafacture-xml/src/main/java/org/metafacture/xml/SerializeEncoder.java index 33fe983f5..d11a1b790 100644 --- a/metafacture-xml/src/main/java/org/metafacture/xml/MarshalEncoder.java +++ b/metafacture-xml/src/main/java/org/metafacture/xml/SerializeEncoder.java @@ -23,11 +23,11 @@ import org.metafacture.framework.annotations.Out; import org.metafacture.framework.helpers.DefaultStreamPipe; -@Description("MarshalEncoder a stream to XML.") +@Description("Converts a Metafacture stream into its XML equivalent.") @In(StreamReceiver.class) @Out(String.class) -@FluxCommand("marshal-to-xml") -public class MarshalEncoder extends DefaultStreamPipe> +@FluxCommand("serialize-to-xml") +public class SerializeEncoder extends DefaultStreamPipe> { final private String xmlDeclaration = ""; final private String spacer = " "; @@ -40,7 +40,7 @@ public class MarshalEncoder extends DefaultStreamPipe> private boolean omitDeclaration = false; private boolean omitRoot = false; - public MarshalEncoder() + public SerializeEncoder() { this.indentation = 0; this.prettyPrint = true; diff --git a/metafacture-xml/src/main/java/org/metafacture/xml/MarshalXmlHandler.java b/metafacture-xml/src/main/java/org/metafacture/xml/SerializeXmlHandler.java similarity index 95% rename from metafacture-xml/src/main/java/org/metafacture/xml/MarshalXmlHandler.java rename to metafacture-xml/src/main/java/org/metafacture/xml/SerializeXmlHandler.java index 27817a66e..350cd55ad 100644 --- a/metafacture-xml/src/main/java/org/metafacture/xml/MarshalXmlHandler.java +++ b/metafacture-xml/src/main/java/org/metafacture/xml/SerializeXmlHandler.java @@ -25,11 +25,11 @@ import org.metafacture.framework.helpers.DefaultXmlPipe; import org.xml.sax.Attributes; -@Description("Unmarshalling a XML stream.") +@Description("Deserialize a XML encoded Metafacture stream.") @In(XmlReceiver.class) @Out(StreamReceiver.class) -@FluxCommand("handle-marshal-xml") -public class MarshalXmlHandler extends DefaultXmlPipe +@FluxCommand("handle-serialize-xml") +public class SerializeXmlHandler extends DefaultXmlPipe { final private String ID = "id"; @@ -40,7 +40,7 @@ public class MarshalXmlHandler extends DefaultXmlPipe private String currentLiteralName; private StringBuilder stringBuilder; - public MarshalXmlHandler() + public SerializeXmlHandler() { streamTagCount = 0; stringBuilder = new StringBuilder(); diff --git a/metafacture-xml/src/main/resources/flux-commands.properties b/metafacture-xml/src/main/resources/flux-commands.properties index 39821eaac..b297736fb 100644 --- a/metafacture-xml/src/main/resources/flux-commands.properties +++ b/metafacture-xml/src/main/resources/flux-commands.properties @@ -15,8 +15,8 @@ # handle-cg-xml org.metafacture.xml.CGXmlHandler handle-generic-xml org.metafacture.xml.GenericXmlHandler -handle-marshal-xml org.metafacture.xml.MarshalXmlHandler -marshal-to-xml org.metafacture.xml.MarshalEncoder +handle-serialize-xml org.metafacture.xml.SerializeXmlHandler +serialize-to-xml org.metafacture.xml.SerializeEncoder stream-to-xml org.metafacture.xml.SimpleXmlEncoder decode-xml org.metafacture.xml.XmlDecoder split-xml-elements org.metafacture.xml.XmlElementSplitter diff --git a/metafacture-xml/src/test/java/org/metafacture/xml/MarshalEncoderTest.java b/metafacture-xml/src/test/java/org/metafacture/xml/SerializeEncoderTest.java similarity index 95% rename from metafacture-xml/src/test/java/org/metafacture/xml/MarshalEncoderTest.java rename to metafacture-xml/src/test/java/org/metafacture/xml/SerializeEncoderTest.java index 8ea3f9ecc..6847c0ff6 100644 --- a/metafacture-xml/src/test/java/org/metafacture/xml/MarshalEncoderTest.java +++ b/metafacture-xml/src/test/java/org/metafacture/xml/SerializeEncoderTest.java @@ -21,13 +21,14 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; + import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.verify; import static org.mockito.internal.verification.VerificationModeFactory.times; -public class MarshalEncoderTest +public class SerializeEncoderTest { - private MarshalEncoder encoder; + private SerializeEncoder encoder; @Mock private ObjectReceiver receiver; @@ -36,12 +37,12 @@ public class MarshalEncoderTest public void setUp() { MockitoAnnotations.initMocks(this); - encoder = new MarshalEncoder(); + encoder = new SerializeEncoder(); encoder.setReceiver(receiver); } @Test - public void marshalling() + public void serialize() { encoder.startRecord("1"); encoder.literal("id", "1"); @@ -78,7 +79,7 @@ public void marshalling() } @Test - public void marshallingWithoutPrettyPrinting() + public void serializeWithoutPrettyPrinting() { encoder.setPrettyPrint(false); @@ -110,7 +111,7 @@ public void marshallingWithoutPrettyPrinting() } @Test - public void marshallingWithNullValue() + public void serializeWithNullValue() { encoder.setPrettyPrint(false); diff --git a/metafacture-xml/src/test/java/org/metafacture/xml/MarshalXmlHandlerTest.java b/metafacture-xml/src/test/java/org/metafacture/xml/SerializeXmlHandlerTest.java similarity index 96% rename from metafacture-xml/src/test/java/org/metafacture/xml/MarshalXmlHandlerTest.java rename to metafacture-xml/src/test/java/org/metafacture/xml/SerializeXmlHandlerTest.java index 81bcb8e7e..96db7a8d8 100644 --- a/metafacture-xml/src/test/java/org/metafacture/xml/MarshalXmlHandlerTest.java +++ b/metafacture-xml/src/test/java/org/metafacture/xml/SerializeXmlHandlerTest.java @@ -25,10 +25,10 @@ import org.xml.sax.helpers.AttributesImpl; import static org.mockito.Mockito.inOrder; -public class MarshalXmlHandlerTest +public class SerializeXmlHandlerTest { - private MarshalXmlHandler handler; + private SerializeXmlHandler handler; @Mock private StreamReceiver receiver; @@ -37,7 +37,7 @@ public class MarshalXmlHandlerTest public void setUp() { MockitoAnnotations.initMocks(this); - handler = new MarshalXmlHandler(); + handler = new SerializeXmlHandler(); handler.setReceiver(receiver); } From 8f4dac722726645a1447333c2c45f85732b502bd Mon Sep 17 00:00:00 2001 From: eberhardtj <30794167+eberhardtj@users.noreply.github.com> Date: Fri, 18 May 2018 09:21:40 +0200 Subject: [PATCH 4/4] Refactoring --- .../org/metafacture/xml/SerializeEncoder.java | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/metafacture-xml/src/main/java/org/metafacture/xml/SerializeEncoder.java b/metafacture-xml/src/main/java/org/metafacture/xml/SerializeEncoder.java index d11a1b790..92a4785b6 100644 --- a/metafacture-xml/src/main/java/org/metafacture/xml/SerializeEncoder.java +++ b/metafacture-xml/src/main/java/org/metafacture/xml/SerializeEncoder.java @@ -34,7 +34,7 @@ public class SerializeEncoder extends DefaultStreamPipe> private boolean initStream; private boolean prettyPrint; - private int indentation; + private int indentationLevel; private StringBuilder stringBuilder; private boolean omitDeclaration = false; @@ -42,7 +42,7 @@ public class SerializeEncoder extends DefaultStreamPipe> public SerializeEncoder() { - this.indentation = 0; + this.indentationLevel = 0; this.prettyPrint = true; this.initStream = true; } @@ -81,7 +81,7 @@ public void startRecord(final String identifier) String elem = ""; if (prettyPrint) { - indentation++; + indentationLevel++; getReceiver().process(spacer + elem); } else @@ -97,8 +97,8 @@ public void startEntity(final String name) String elem = ""; if (prettyPrint) { - indentation++; - getReceiver().process(separators(indentation, spacer) + elem); + indentationLevel++; + getReceiver().process(repeat(spacer, indentationLevel) + elem); } else { @@ -112,7 +112,7 @@ public void literal(final String name, final String value) String elem = "" + escape(value) + ""; if (prettyPrint) { - getReceiver().process(separators(indentation+1, spacer) + elem); + getReceiver().process(repeat(spacer, indentationLevel + 1) + elem); } else { @@ -126,8 +126,8 @@ public void endEntity() String elem = ""; if (prettyPrint) { - getReceiver().process(separators(indentation, spacer) + elem); - indentation--; + getReceiver().process(repeat(spacer, indentationLevel) + elem); + indentationLevel--; } else { @@ -142,7 +142,7 @@ public void endRecord() if (prettyPrint) { getReceiver().process(spacer + ""); - indentation--; + indentationLevel--; } else { @@ -163,16 +163,19 @@ public void onCloseStream() @Override public void onResetStream() { - this.indentation = 0; + this.indentationLevel = 0; this.initStream = true; } - private String separators(int amount, String separator) + /** + * Build a String consists of {@code n} repetitions of a String {@code s}. + */ + private String repeat(String s, int n) { - StringBuilder sb = new StringBuilder(separator); - for (int i = 0; i < amount - 1; i++) + StringBuilder sb = new StringBuilder(s); + for (int i = 0; i < n - 1; i++) { - sb.append(separator); + sb.append(s); } return sb.toString(); }