diff --git a/src/main/java/net/openhft/chronicle/wire/WireMarshaller.java b/src/main/java/net/openhft/chronicle/wire/WireMarshaller.java index 23b27f3e7..9332643ed 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireMarshaller.java +++ b/src/main/java/net/openhft/chronicle/wire/WireMarshaller.java @@ -345,7 +345,7 @@ public void readMarshallableInputOrder(T t, @NotNull WireIn in, T defaults, bool } public boolean matchesFieldName(StringBuilder sb, FieldAccess field) { - return sb.length() == 0 || StringUtils.isEqual(field.field.getName(), sb); + return sb.length() == 0 || StringUtils.equalsCaseIgnore(field.field.getName(), sb); } public void writeKey(T t, Bytes bytes) { diff --git a/src/main/java/net/openhft/chronicle/wire/YamlTokeniser.java b/src/main/java/net/openhft/chronicle/wire/YamlTokeniser.java index 8e27c947a..5d3e58770 100644 --- a/src/main/java/net/openhft/chronicle/wire/YamlTokeniser.java +++ b/src/main/java/net/openhft/chronicle/wire/YamlTokeniser.java @@ -73,6 +73,7 @@ void reset() { blockQuote = 0; hasSequenceEntry = false; lastKeyPosition = -1; + pushed.clear(); last = YamlToken.STREAM_START; pushContext0(YamlToken.STREAM_START, NO_INDENT); } @@ -660,6 +661,10 @@ public long lineStart() { return lineStart; } + public void lineStart(long lineStart) { + this.lineStart = lineStart; + } + public long blockStart() { return blockStart; } diff --git a/src/main/java/net/openhft/chronicle/wire/YamlWire.java b/src/main/java/net/openhft/chronicle/wire/YamlWire.java index a401e0054..c9cbea558 100644 --- a/src/main/java/net/openhft/chronicle/wire/YamlWire.java +++ b/src/main/java/net/openhft/chronicle/wire/YamlWire.java @@ -196,6 +196,7 @@ public T methodWriter(@NotNull Class tClass, Class... additional) { () -> newTextMethodWriterInvocationHandler(tClass)); for (Class aClass : additional) builder.addInterface(aClass); + useTextDocuments(); builder.marshallableOut(this); return builder.build(); } @@ -252,6 +253,7 @@ protected void initReadContext() { if (readContext == null) useBinaryDocuments(); readContext.start(); + yt.lineStart(bytes.readPosition()); } @NotNull @@ -453,6 +455,10 @@ protected StringBuilder readField(@NotNull StringBuilder sb) { public K readEvent(@NotNull Class expectedClass) throws InvalidMarshallableException { startEventIfTop(); switch (yt.current()) { + case MAPPING_START: + yt.next(); + assert yt.current() == YamlToken.MAPPING_KEY; + // Deliberate fall-through case MAPPING_KEY: YamlToken next = yt.next(); if (next == YamlToken.MAPPING_KEY) { @@ -539,6 +545,7 @@ public ValueIn read(String keyName) { return rereadWire.valueIn; } } + // Next lines not covered by any tests } YamlTokeniser.YTContext yc = yt.topContext(); int minIndent = yc.indent; @@ -550,7 +557,8 @@ public ValueIn read(String keyName) { if (!StringUtils.startsWith(sb, "-")) keys.push(lastKeyPosition); - valueIn.consumeAny(minIndent); + // Avoid consuming '}' but consume to next mapping key + valueIn.consumeAny(minIndent >= 0 ? minIndent : Integer.MAX_VALUE); } return defaultValueIn; @@ -610,11 +618,10 @@ public ValueIn getValueIn() { @NotNull @Override public Wire readComment(@NotNull StringBuilder s) { - sb.setLength(0); + s.setLength(0); if (yt.current() == YamlToken.COMMENT) { - // Skip the initial '#' - YamlToken next = yt.next(); - sb.append(yt.text()); + s.append(yt.text()); + yt.next(); } return this; } @@ -753,11 +760,12 @@ public void endEvent() { yt.next(Integer.MIN_VALUE); } else { while (yt.current() == YamlToken.MAPPING_KEY) { - yt.next(); valueIn.consumeAny(minIndent); } } - if (yt.current() == YamlToken.MAPPING_END || yt.current() == YamlToken.DOCUMENT_END || yt.current() == YamlToken.NONE) { + if (yt.current() == YamlToken.MAPPING_END || + yt.current() == YamlToken.DOCUMENT_END || + yt.current() == YamlToken.NONE) { yt.next(Integer.MIN_VALUE); return; } @@ -1344,7 +1352,6 @@ public WireIn sequence(@NotNull T t, K kls, @NotNull TriConsumer WireIn typeLiteralAsText(T t, @NotNull BiConsumer classNameConsumer) throws IORuntimeException, BufferUnderflowException { - throw new UnsupportedOperationException(yt.toString()); + if (yt.current() != YamlToken.TAG) + throw new UnsupportedOperationException(yt.toString()); + + if (!yt.isText("type")) + throw new UnsupportedOperationException(yt.text()); + + if (yt.next() != YamlToken.TEXT) + throw new UnsupportedOperationException(yt.toString()); + + StringBuilder stringBuilder = acquireStringBuilder(); + textTo(stringBuilder); + classNameConsumer.accept(t, stringBuilder); + + return YamlWire.this; } @Override diff --git a/src/test/java/net/openhft/chronicle/wire/DeserializeFromNakedFileTest.java b/src/test/java/net/openhft/chronicle/wire/DeserializeFromNakedFileTest.java index 3bf2e4035..910ccd0ef 100644 --- a/src/test/java/net/openhft/chronicle/wire/DeserializeFromNakedFileTest.java +++ b/src/test/java/net/openhft/chronicle/wire/DeserializeFromNakedFileTest.java @@ -20,29 +20,51 @@ import net.openhft.chronicle.bytes.BytesMarshallable; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeFalse; +@RunWith(value = Parameterized.class) public class DeserializeFromNakedFileTest extends WireTestCommon { + private final WireType wireType; + + public DeserializeFromNakedFileTest(WireType wireType) { + this.wireType = wireType; + } + + @Parameterized.Parameters(name = "{0}") + public static Collection combinations() { + Object[][] list = { + {WireType.TEXT}, + {WireType.YAML} + }; + return Arrays.asList(list); + } + @Test public void testPOJO() throws IOException { - PlainOldJavaClass res = Marshallable.fromFile(PlainOldJavaClass.class, "naked.yaml"); + PlainOldJavaClass res = wireType.fromFile(PlainOldJavaClass.class, "naked.yaml"); assertEquals(20, res.heartBtInt); } @Test public void testSelfDescribing() throws IOException { - SelfDescribingClass res = Marshallable.fromFile(SelfDescribingClass.class, "naked.yaml"); + SelfDescribingClass res = wireType.fromFile(SelfDescribingClass.class, "naked.yaml"); assertEquals(20, res.heartBtInt); } @Test public void testBytes() throws IOException { - BytesClass res = Marshallable.fromFile(BytesClass.class, "naked.yaml"); + assumeFalse(wireType == WireType.YAML); + BytesClass res = wireType.fromFile(BytesClass.class, "naked.yaml"); // The result of parsing first 4 bytes as integer value assertEquals(0x72616548, res.heartBtInt); diff --git a/src/test/java/net/openhft/chronicle/wire/ForwardAndBackwardCompatibilityMarshallableTest.java b/src/test/java/net/openhft/chronicle/wire/ForwardAndBackwardCompatibilityMarshallableTest.java index 606ae785b..08a1a85cf 100644 --- a/src/test/java/net/openhft/chronicle/wire/ForwardAndBackwardCompatibilityMarshallableTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ForwardAndBackwardCompatibilityMarshallableTest.java @@ -23,6 +23,7 @@ import net.openhft.chronicle.core.util.StringUtils; import org.jetbrains.annotations.NotNull; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -41,13 +42,12 @@ public ForwardAndBackwardCompatibilityMarshallableTest(WireType wireType) { this.wireType = wireType; } - @Parameterized.Parameters + @Parameterized.Parameters(name = "{0}") public static Collection data() { return Arrays.asList(new Object[][]{ {WireType.JSON}, {WireType.TEXT}, - // TODO FIX -// {WireType.YAML}, + {WireType.YAML}, {WireType.BINARY} }); } @@ -63,15 +63,12 @@ public void marshableStringBuilderTest() throws Exception { wire.writeDocument(false, w -> new MDTO2(1, 2, "3").writeMarshallable(w)); // System.out.println(Wires.fromSizePrefixedBlobs(wire)); - if (wire instanceof TextWire) - ((TextWire) wire).useBinaryDocuments(); - try (DocumentContext dc = wire.readingDocument()) { if (!dc.isPresent()) Assert.fail(); @NotNull MDTO2 dto2 = new MDTO2(); dto2.readMarshallable(dc.wire()); - Assert.assertEquals(1, dto2.one ); + Assert.assertEquals(1, dto2.one); Assert.assertEquals(2, dto2.two); Assert.assertTrue("3".contentEquals(dto2.three)); } @@ -112,6 +109,7 @@ public void backwardsCompatibility() { public void forwardCompatibility() { final Wire wire = wireType.apply(Bytes.elasticByteBuffer()); + Assume.assumeFalse(wire instanceof YamlWire); wire.usePadding(wire.isBinary()); ClassLookup wrap2 = CLASS_ALIASES.wrap(); wrap2.addAlias(MDTO2.class, "MDTO"); @@ -126,8 +124,6 @@ public void forwardCompatibility() { if (wire instanceof TextWire) ((TextWire) wire).useBinaryDocuments(); - if (wire instanceof YamlWire) - ((YamlWire) wire).useBinaryDocuments(); try (DocumentContext dc = wire.readingDocument()) { if (!dc.isPresent()) Assert.fail(); diff --git a/src/test/java/net/openhft/chronicle/wire/NestedMapsTest.java b/src/test/java/net/openhft/chronicle/wire/NestedMapsTest.java index 5188680da..e9c6470ae 100644 --- a/src/test/java/net/openhft/chronicle/wire/NestedMapsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/NestedMapsTest.java @@ -38,13 +38,12 @@ public NestedMapsTest(WireType wireType) { this.wireType = wireType; } - @Parameterized.Parameters + @Parameterized.Parameters(name = "{0}") public static Collection wireTypes() { return Arrays.asList( new Object[]{WireType.JSON}, new Object[]{WireType.TEXT}, - // TODO FIX -// new Object[]{WireType.YAML_ONLY}, + new Object[]{WireType.YAML_ONLY}, new Object[]{WireType.BINARY}, new Object[]{WireType.FIELDLESS_BINARY} ); diff --git a/src/test/java/net/openhft/chronicle/wire/TextBinaryWireTest.java b/src/test/java/net/openhft/chronicle/wire/TextBinaryWireTest.java index 524813936..c9bfbe5b4 100644 --- a/src/test/java/net/openhft/chronicle/wire/TextBinaryWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TextBinaryWireTest.java @@ -31,6 +31,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; @RunWith(value = Parameterized.class) public class TextBinaryWireTest extends WireTestCommon { @@ -42,13 +44,14 @@ public TextBinaryWireTest(WireType wireType) { this.wireType = wireType; } - @Parameterized.Parameters + @Parameterized.Parameters(name = "{0}") public static Collection combinations() { Object[][] list = { {WireType.BINARY}, {WireType.FIELDLESS_BINARY}, {WireType.RAW}, {WireType.TEXT}, + {WireType.YAML}, {WireType.JSON} }; return Arrays.asList(list); @@ -87,21 +90,21 @@ public void readingDocumentLocation() { @Test public void testReadComment() { - if (wireType == WireType.TEXT || wireType == WireType.BINARY) { - Wire wire = createWire(); - wire.writeComment("This is a comment"); - @NotNull StringBuilder sb = new StringBuilder(); - wire.readComment(sb); - assertEquals("This is a comment", sb.toString()); - - wire.bytes().releaseLast(); - } + assumeTrue(wireType == WireType.TEXT || wireType == WireType.BINARY || wireType == WireType.YAML); + + Wire wire = createWire(); + wire.writeComment("This is a comment"); + @NotNull StringBuilder sb = new StringBuilder(); + wire.readComment(sb); + assertEquals("This is a comment", sb.toString()); + + wire.bytes().releaseLast(); } @Test public void readFieldAsObject() { - if (wireType == WireType.RAW || wireType == WireType.FIELDLESS_BINARY) - return; + assumeFalse(wireType == WireType.RAW || wireType == WireType.FIELDLESS_BINARY); + Wire wire = createWire(); wire.write("CLASS").text("class") .write("RUNTIME").text("runtime"); @@ -117,8 +120,8 @@ public void readFieldAsObject() { @Test public void readFieldAsLong() { - if (wireType == WireType.RAW || wireType == WireType.FIELDLESS_BINARY) - return; + assumeFalse(wireType == WireType.RAW || wireType == WireType.FIELDLESS_BINARY); + Wire wire = createWire(); // todo fix to ensure a field number is used. wire.writeEvent(Long.class, 1L).text("class") @@ -138,8 +141,7 @@ public void readFieldAsLong() { @Test public void testConvertToNum() { - if (wireType == WireType.RAW) - return; + assumeFalse(wireType == WireType.RAW || /* No support for bool conversions */ wireType == WireType.YAML); Wire wire = createWire(); wire.write("a").bool(false) diff --git a/src/test/java/net/openhft/chronicle/wire/WireSerializedLambdaTest.java b/src/test/java/net/openhft/chronicle/wire/WireSerializedLambdaTest.java index fda478559..d2d82e32c 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireSerializedLambdaTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireSerializedLambdaTest.java @@ -98,7 +98,6 @@ public void testTextWire() { doTestText(WireType.TEXT); } - @Ignore(/* TODO FIX */) @Test public void testYamlWire() { doTestText(WireType.YAML_ONLY); diff --git a/src/test/java/net/openhft/chronicle/wire/reordered/NestedClass.java b/src/test/java/net/openhft/chronicle/wire/reordered/NestedClass.java index 839826b05..eb50e9940 100644 --- a/src/test/java/net/openhft/chronicle/wire/reordered/NestedClass.java +++ b/src/test/java/net/openhft/chronicle/wire/reordered/NestedClass.java @@ -29,11 +29,13 @@ public class NestedClass implements Marshallable { double number; double number2; double number4; // out of order + NestedClass doublyNested; @Override public void readMarshallable(@NotNull WireIn wire) throws IORuntimeException { wire.read(() -> "text").text(this, (t, v) -> t.text = v) .read(() -> "text2").text(this, (t, v) -> t.text2 = v) + .read(() -> "doublyNested").object(NestedClass.class, this, (t, v) -> t.doublyNested = v) .read(() -> "number").float64(this, (t, v) -> t.number = v) .read(() -> "number2").float64(this, (t, v) -> t.number2 = v) .read(() -> "number4").float64(this, (t, v) -> t.number4 = v); @@ -46,13 +48,19 @@ public void writeMarshallable(@NotNull WireOut wire) { .write(() -> "text3").text("is text3") .write(() -> "number4").float64(number4) .write(() -> "number").float64(number) + .write(() -> "doublyNested").object(doublyNested) .write(() -> "number3").float64(333.3); } - public void setTextNumber(String text, double number) { + public NestedClass setTextNumber(String text, double number) { this.text = text; this.number = number; this.number4 = number * 4; + return this; + } + + public void nest(String text, double number) { + this.doublyNested = new NestedClass().setTextNumber(text, number); } @NotNull diff --git a/src/test/java/net/openhft/chronicle/wire/reordered/NestedReadSubset.java b/src/test/java/net/openhft/chronicle/wire/reordered/NestedReadSubset.java new file mode 100644 index 000000000..b6466b71b --- /dev/null +++ b/src/test/java/net/openhft/chronicle/wire/reordered/NestedReadSubset.java @@ -0,0 +1,68 @@ +/* + * Copyright 2016-2020 chronicle.software + * + * https://chronicle.software + * + * 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 net.openhft.chronicle.wire.reordered; + +import net.openhft.chronicle.core.io.IORuntimeException; +import net.openhft.chronicle.wire.Marshallable; +import net.openhft.chronicle.wire.WireIn; +import net.openhft.chronicle.wire.WireOut; +import org.jetbrains.annotations.NotNull; + +public class NestedReadSubset implements Marshallable { + String text; + String text2; + double number; + double number2; + double number4; + + @Override + public void readMarshallable(@NotNull WireIn wire) throws IORuntimeException { + String text = wire.read("text").text(); + double number = wire.read("number").float64(); + setTextNumber(text, number); + } + + @Override + public void writeMarshallable(@NotNull WireOut wire) { + // write version has way more fields + wire.write(() -> "text").text(text) + .write(() -> "number").float64(number) + .write(() -> "text3").text("is text3") + .write(() -> "number4").float64(number4) + .write(() -> "number3").float64(333.3); + } + + public NestedReadSubset setTextNumber(String text, double number) { + this.text = text; + this.number = number; + this.number4 = number * 4; + return this; + } + + @NotNull + @Override + public String toString() { + return "NestedReadSubset{" + + "text='" + text + '\'' + + ", text2='" + text2 + '\'' + + ", number=" + number + + ", number2=" + number2 + + ", number4=" + number4 + + '}'; + } +} diff --git a/src/test/java/net/openhft/chronicle/wire/reordered/ReorderedTest.java b/src/test/java/net/openhft/chronicle/wire/reordered/ReorderedTest.java index bd291d565..88425c5cd 100644 --- a/src/test/java/net/openhft/chronicle/wire/reordered/ReorderedTest.java +++ b/src/test/java/net/openhft/chronicle/wire/reordered/ReorderedTest.java @@ -26,6 +26,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.function.Function; @@ -47,28 +48,33 @@ public class ReorderedTest extends WireTestCommon { outerClass1.clearListB(); outerClass2.clearListB(); outerClass1.addListA().setTextNumber("num1A", 11); - outerClass1.addListB().setTextNumber("num1B", 12); - outerClass1.addListA().setTextNumber("num1AA", 111); + outerClass1.addListB().setTextNumber("num1B", 12).nest("num1Bbis", 121); + outerClass1.addListA().setTextNumber("num1AA", 111).nest("num1AAbis", 1111); outerClass1.addListB().setTextNumber("num1BB", 122); outerClass2.addListA().setTextNumber("num2A", 21); - outerClass2.addListB().setTextNumber("num2B", 22); + outerClass2.addListB().setTextNumber("num2B", 22).nest("num2Bbis", 222); + + nestedReadSubsets = Arrays.asList( + new NestedReadSubset().setTextNumber("one", 1.1), + new NestedReadSubset().setTextNumber("two", 2.2)); } @SuppressWarnings("rawtypes") private final Function, Wire> wireType; + private static final Collection nestedReadSubsets; @SuppressWarnings("rawtypes") public ReorderedTest(Function, Wire> wireType) { this.wireType = wireType; } - @Parameterized.Parameters + @Parameterized.Parameters(name = "{0}") public static Collection combinations() { return Arrays.asList(new Object[][]{ {WireType.JSON}, {WireType.TEXT}, - // TODO FIX - // {WireType.YAML_ONLY}, + // https://github.com/OpenHFT/Chronicle-Wire/issues/665 + //{WireType.YAML_ONLY}, {WireType.BINARY} }); } @@ -98,6 +104,18 @@ public void testWithReorderedFields() { bytes.releaseLast(); } + @Test + public void testWithSubsetFields() { + Bytes bytes = Bytes.elasticByteBuffer(); + Wire wire = wireType.apply(bytes); + wire.writeEventName(() -> "test1").collection(nestedReadSubsets, NestedReadSubset.class); + + @NotNull StringBuilder sb = new StringBuilder(); + + assertEquals(nestedReadSubsets.toString().replace(',', '\n'), wire.readEventName(sb).collection(ArrayList::new, NestedReadSubset.class).toString().replace(',', '\n')); + assertEquals("test1", sb.toString()); + } + @SuppressWarnings("rawtypes") @Test public void testTopLevel() {