From 0bb8271b72f729d069c1201ab8ef9901c4727ffb Mon Sep 17 00:00:00 2001 From: Jerry Shea Date: Wed, 18 Dec 2024 07:34:10 +1100 Subject: [PATCH] fix recycling of MethodReader args for proxies. Closes #980 --- .../chronicle/wire/VanillaMethodReader.java | 9 ++++- ...MethodReaderArgumentsRecycleProxyTest.java | 36 +++++++++++++++++++ .../MethodReaderArgumentsRecycleTest.java | 33 +++++++++++++++-- 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleProxyTest.java diff --git a/src/main/java/net/openhft/chronicle/wire/VanillaMethodReader.java b/src/main/java/net/openhft/chronicle/wire/VanillaMethodReader.java index 0773443eb..26f21108a 100644 --- a/src/main/java/net/openhft/chronicle/wire/VanillaMethodReader.java +++ b/src/main/java/net/openhft/chronicle/wire/VanillaMethodReader.java @@ -677,7 +677,14 @@ private T checkRecycle(T o) { ((Collection) o).clear(); return o; } - // If object is Marshallable, return the same object, else return null + if (o instanceof Map) { + ((Map) o).clear(); + return o; + } + // For objects of type AbstractMarshallableCfg, reset them to their default state. + if (o instanceof AbstractMarshallableCfg) { + ((AbstractMarshallableCfg) o).reset(); + } return o instanceof Marshallable ? o : null; } diff --git a/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleProxyTest.java b/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleProxyTest.java new file mode 100644 index 000000000..9fd0ae3a9 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleProxyTest.java @@ -0,0 +1,36 @@ +/* + * 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; + +import org.junit.After; + +// Test class extending MethodReaderArgumentsRecycleTest to test behavior of method readers when using proxies +public class MethodReaderArgumentsRecycleProxyTest extends MethodReaderArgumentsRecycleTest { + @Override + public void setUp() { + // Disable proxy code generation for the duration of the tests + System.setProperty("disableReaderProxyCodegen", "true"); + super.setUp(); + } + + @After + public void after() { + // Clear the property to re-enable proxy code generation + System.clearProperty("disableReaderProxyCodegen"); + } +} diff --git a/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleTest.java b/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleTest.java index a78ce2f11..311f8c38a 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleTest.java @@ -19,6 +19,7 @@ import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.bytes.MethodReader; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -77,6 +78,11 @@ public void dtoCall(RegularDTO d) { lastArgumentRef = d; } + @Override + public void configDtoCall(ConfigDTO d) { + lastArgumentRef = d; + } + @Override public void wrappedListCall(ListContainingDto ld) { lastArgumentRef = ld; @@ -197,6 +203,22 @@ public void testDtoRecycled() { verifyRecycled(first, second, writer::dtoCall); } + @Test + public void testConfigDtoRecycled() { + ConfigDTO first = new ConfigDTO(); + first.s = "f"; + first.b = true; + + ConfigDTO second = new ConfigDTO(); + second.s = "s"; + // don't set b + + verifyRecycled(first, second, writer::configDtoCall); + + ConfigDTO dto = (ConfigDTO) lastArgumentRef; + Assert.assertFalse(dto.b); + } + // Test to ascertain that a DTO object's list field gets recycled between calls. @Test public void testWrappedListRecycled() { @@ -258,8 +280,8 @@ public void testWrappedListAsObjectRecycledDTO() { "}\n", lastArgumentRef.toString()); List list2 = (List) ((ObjectContainingDto) lastArgumentRef).list; assertEquals(second.list, list2); - assertSame(dto0, (MyDto) list1.get(0)); - assertSame(dto1, (MyDto) list1.get(1)); + assertSame(dto0, list1.get(0)); + assertSame(dto1, list1.get(1)); // Ensure the reference from the first call is the same as the second. assertSame(firstRef, lastArgumentRef); @@ -322,6 +344,8 @@ interface MyInterface { void dtoCall(RegularDTO d); + void configDtoCall(ConfigDTO d); + void wrappedListCall(ListContainingDto ld); void wrappedObjectCall(ObjectContainingDto ld); @@ -349,6 +373,11 @@ public static class RegularDTO extends SelfDescribingMarshallable { int i; } + public static class ConfigDTO extends AbstractMarshallableCfg { + String s; + boolean b; + } + // Definition of a DTO with a list-containing field. public static class ListContainingDto extends SelfDescribingMarshallable { List list;