From d1246e598b2bef533bc87d0d4ceef3494a24cdd4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:09:55 +0000 Subject: [PATCH 1/6] Initial plan From 27f31d5b9f83b0d5ee16e108cffd9fb9b49b6718 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:14:15 +0000 Subject: [PATCH 2/6] Initial analysis of generic field issue Co-authored-by: huayanYu <16700837+huayanYu@users.noreply.github.com> --- .../jsonzou/jmockdata/TestGenericIssue.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/test/java/com/github/jsonzou/jmockdata/TestGenericIssue.java diff --git a/src/test/java/com/github/jsonzou/jmockdata/TestGenericIssue.java b/src/test/java/com/github/jsonzou/jmockdata/TestGenericIssue.java new file mode 100644 index 000000000..9b5dc1a0b --- /dev/null +++ b/src/test/java/com/github/jsonzou/jmockdata/TestGenericIssue.java @@ -0,0 +1,42 @@ +package com.github.jsonzou.jmockdata; + +import org.junit.Test; +import java.util.List; + +import static org.junit.Assert.assertNotNull; + +public class TestGenericIssue { + + @Test + public void testGeneric() { + final GeneralEntity entity = JMockData.mock(GeneralEntity.class); + assertNotNull(entity); + assertNotNull(entity.getRows()); + System.out.println("Test passed! Rows: " + entity.getRows()); + } + +} + +class GeneralEntity{ + private List> rows; + + public List> getRows() { + return rows; + } + + public void setRows(List> rows) { + this.rows = rows; + } +} + +class GenericEntity { + private T key; + + public T getKey() { + return key; + } + + public void setKey(T key) { + this.key = key; + } +} From a4343e58ff3c0690e78bf45fba43647aebb9dbd4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:16:42 +0000 Subject: [PATCH 3/6] Fix generic field mocking by passing generic types to BeanMocker Co-authored-by: huayanYu <16700837+huayanYu@users.noreply.github.com> --- .../github/jsonzou/jmockdata/MockConfig.java | 8 ++++ .../jsonzou/jmockdata/mocker/BeanMocker.java | 44 ++++++++++++++++++- .../jsonzou/jmockdata/mocker/ClassMocker.java | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/github/jsonzou/jmockdata/MockConfig.java b/src/main/java/com/github/jsonzou/jmockdata/MockConfig.java index 7f66c426a..719cbb82d 100644 --- a/src/main/java/com/github/jsonzou/jmockdata/MockConfig.java +++ b/src/main/java/com/github/jsonzou/jmockdata/MockConfig.java @@ -114,6 +114,14 @@ public Object getcacheBean(String beanClassName) { return beanCache.get(beanClassName); } + public void cacheTypeVariable(String name, Type type) { + typeVariableCache.put(name, type); + } + + public void removeTypeVariable(String name) { + typeVariableCache.remove(name); + } + public void cacheEnum(String name, Enum[] enums) { enumCache.put(name, enums); } diff --git a/src/main/java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java b/src/main/java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java index e2c9a3613..13215f10d 100644 --- a/src/main/java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java +++ b/src/main/java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java @@ -8,6 +8,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -17,9 +19,15 @@ public class BeanMocker implements Mocker { private Map, List> classFieldCache = new ConcurrentHashMap<>((int)((float)32 / 0.75F + 1.0F)); private final Class clazz; + private final Type[] genericTypes; BeanMocker(Class clazz) { + this(clazz, null); + } + + BeanMocker(Class clazz, Type[] genericTypes) { this.clazz = clazz; + this.genericTypes = genericTypes; } @Override @@ -41,7 +49,41 @@ public Object mock(DataConfig mockConfig) { if(mockConfig.globalConfig().isConfigExcludeMock(clazz)){ return result; } - setFieldValueByFieldAccessible(mockConfig, result); + // Initialize type variable cache if generic types are provided + Map savedTypeVariables = null; + if (genericTypes != null && genericTypes.length > 0) { + TypeVariable[] typeVariables = clazz.getTypeParameters(); + if (typeVariables != null && typeVariables.length > 0) { + // Save current type variable mappings + savedTypeVariables = new java.util.HashMap<>(); + for (int index = 0; index < Math.min(typeVariables.length, genericTypes.length); index++) { + String varName = typeVariables[index].getName(); + Type oldValue = mockConfig.globalConfig().getVariableType(varName); + if (oldValue != null) { + savedTypeVariables.put(varName, oldValue); + } + mockConfig.globalConfig().cacheTypeVariable(varName, genericTypes[index]); + } + } + } + try { + setFieldValueByFieldAccessible(mockConfig, result); + } finally { + // Restore previous type variable mappings + if (savedTypeVariables != null) { + TypeVariable[] typeVariables = clazz.getTypeParameters(); + if (typeVariables != null && typeVariables.length > 0) { + for (int index = 0; index < Math.min(typeVariables.length, genericTypes.length); index++) { + String varName = typeVariables[index].getName(); + if (savedTypeVariables.containsKey(varName)) { + mockConfig.globalConfig().cacheTypeVariable(varName, savedTypeVariables.get(varName)); + } else { + mockConfig.globalConfig().removeTypeVariable(varName); + } + } + } + } + } return result; } catch (Exception e) { throw new MockException(e); diff --git a/src/main/java/com/github/jsonzou/jmockdata/mocker/ClassMocker.java b/src/main/java/com/github/jsonzou/jmockdata/mocker/ClassMocker.java index 2ec273b2b..871adf15f 100644 --- a/src/main/java/com/github/jsonzou/jmockdata/mocker/ClassMocker.java +++ b/src/main/java/com/github/jsonzou/jmockdata/mocker/ClassMocker.java @@ -32,7 +32,7 @@ public Object mock(DataConfig mockConfig) { } else { mocker = mockConfig.globalConfig().getMocker(clazz); if (mocker == null) { - mocker = new BeanMocker(clazz); + mocker = new BeanMocker(clazz, genericTypes); } } return mocker.mock(mockConfig); From fc45f3d18ce5c1e031da94ec5b44a0b1603334c9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:17:40 +0000 Subject: [PATCH 4/6] Add test case for generic field mocking in JMockDataTest Co-authored-by: huayanYu <16700837+huayanYu@users.noreply.github.com> --- .../jsonzou/jmockdata/JMockDataTest.java | 52 +++++++++++++++++++ .../jsonzou/jmockdata/TestGenericIssue.java | 42 --------------- 2 files changed, 52 insertions(+), 42 deletions(-) delete mode 100644 src/test/java/com/github/jsonzou/jmockdata/TestGenericIssue.java diff --git a/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java b/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java index 3741dda25..98a212dbf 100644 --- a/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java +++ b/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java @@ -121,6 +121,58 @@ public void testGenericData() { assertNotNull(genericData); } + /** + * Test for issue: 普通对象包含含有泛型字段的集合时mock失败 + * Test mocking a bean with a field containing a parameterized generic type + */ + @Test + public void testGenericFieldInCollection() { + // Create a simple bean that contains List> + class GeneralEntity { + private List> rows; + + public List> getRows() { + return rows; + } + + public void setRows(List> rows) { + this.rows = rows; + } + } + + class GenericEntity { + private T key; + + public T getKey() { + return key; + } + + public void setKey(T key) { + this.key = key; + } + } + + GeneralEntity entity = JMockData.mock(GeneralEntity.class); + assertNotNull(entity); + assertNotNull(entity.getRows()); + assertFalse(entity.getRows().isEmpty()); + + // Verify that the generic field in GenericEntity is properly mocked + Object firstItem = entity.getRows().get(0); + assertNotNull(firstItem); + // Use reflection to get the key field since we can't directly access it due to local class + try { + java.lang.reflect.Field keyField = firstItem.getClass().getDeclaredField("key"); + keyField.setAccessible(true); + Object key = keyField.get(firstItem); + assertNotNull(key); + assertTrue(key instanceof String); + System.out.println("Generic field test passed! Key type: " + key.getClass().getName()); + } catch (Exception e) { + fail("Failed to access key field: " + e.getMessage()); + } + } + @Test public void testMockConfig() { MockConfig mockConfig = new MockConfig() diff --git a/src/test/java/com/github/jsonzou/jmockdata/TestGenericIssue.java b/src/test/java/com/github/jsonzou/jmockdata/TestGenericIssue.java deleted file mode 100644 index 9b5dc1a0b..000000000 --- a/src/test/java/com/github/jsonzou/jmockdata/TestGenericIssue.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.github.jsonzou.jmockdata; - -import org.junit.Test; -import java.util.List; - -import static org.junit.Assert.assertNotNull; - -public class TestGenericIssue { - - @Test - public void testGeneric() { - final GeneralEntity entity = JMockData.mock(GeneralEntity.class); - assertNotNull(entity); - assertNotNull(entity.getRows()); - System.out.println("Test passed! Rows: " + entity.getRows()); - } - -} - -class GeneralEntity{ - private List> rows; - - public List> getRows() { - return rows; - } - - public void setRows(List> rows) { - this.rows = rows; - } -} - -class GenericEntity { - private T key; - - public T getKey() { - return key; - } - - public void setKey(T key) { - this.key = key; - } -} From f384257ba84b78faa34c43c87ceb2417084959a1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:21:07 +0000 Subject: [PATCH 5/6] Add bean classes and complete test for generic field mocking Co-authored-by: huayanYu <16700837+huayanYu@users.noreply.github.com> --- .../jsonzou/jmockdata/JMockDataTest.java | 47 ++++--------------- .../jsonzou/jmockdata/bean/GeneralBean.java | 19 ++++++++ .../jmockdata/bean/GenericFieldEntity.java | 16 +++++++ 3 files changed, 43 insertions(+), 39 deletions(-) create mode 100644 src/test/java/com/github/jsonzou/jmockdata/bean/GeneralBean.java create mode 100644 src/test/java/com/github/jsonzou/jmockdata/bean/GenericFieldEntity.java diff --git a/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java b/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java index 98a212dbf..8b33c3cea 100644 --- a/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java +++ b/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java @@ -127,50 +127,19 @@ public void testGenericData() { */ @Test public void testGenericFieldInCollection() { - // Create a simple bean that contains List> - class GeneralEntity { - private List> rows; - - public List> getRows() { - return rows; - } - - public void setRows(List> rows) { - this.rows = rows; - } - } - - class GenericEntity { - private T key; - - public T getKey() { - return key; - } - - public void setKey(T key) { - this.key = key; - } - } - - GeneralEntity entity = JMockData.mock(GeneralEntity.class); + GeneralBean entity = JMockData.mock(GeneralBean.class); assertNotNull(entity); assertNotNull(entity.getRows()); assertFalse(entity.getRows().isEmpty()); - // Verify that the generic field in GenericEntity is properly mocked - Object firstItem = entity.getRows().get(0); + // Verify that the generic field in GenericFieldEntity is properly mocked + GenericFieldEntity firstItem = entity.getRows().get(0); assertNotNull(firstItem); - // Use reflection to get the key field since we can't directly access it due to local class - try { - java.lang.reflect.Field keyField = firstItem.getClass().getDeclaredField("key"); - keyField.setAccessible(true); - Object key = keyField.get(firstItem); - assertNotNull(key); - assertTrue(key instanceof String); - System.out.println("Generic field test passed! Key type: " + key.getClass().getName()); - } catch (Exception e) { - fail("Failed to access key field: " + e.getMessage()); - } + assertNotNull(firstItem.getKey()); + assertTrue(firstItem.getKey() instanceof String); + + System.out.println("Generic field test passed! Key type: " + firstItem.getKey().getClass().getName()); + System.out.println("Key value: " + firstItem.getKey()); } @Test diff --git a/src/test/java/com/github/jsonzou/jmockdata/bean/GeneralBean.java b/src/test/java/com/github/jsonzou/jmockdata/bean/GeneralBean.java new file mode 100644 index 000000000..c0098fdfb --- /dev/null +++ b/src/test/java/com/github/jsonzou/jmockdata/bean/GeneralBean.java @@ -0,0 +1,19 @@ +package com.github.jsonzou.jmockdata.bean; + +import java.util.List; + +/** + * Bean containing a list of generic entities + * Used to test the fix for issue: 普通对象包含含有泛型字段的集合时mock失败 + */ +public class GeneralBean { + private List> rows; + + public List> getRows() { + return rows; + } + + public void setRows(List> rows) { + this.rows = rows; + } +} diff --git a/src/test/java/com/github/jsonzou/jmockdata/bean/GenericFieldEntity.java b/src/test/java/com/github/jsonzou/jmockdata/bean/GenericFieldEntity.java new file mode 100644 index 000000000..de1411aa8 --- /dev/null +++ b/src/test/java/com/github/jsonzou/jmockdata/bean/GenericFieldEntity.java @@ -0,0 +1,16 @@ +package com.github.jsonzou.jmockdata.bean; + +/** + * Generic entity with a parameterized type field + */ +public class GenericFieldEntity { + private T key; + + public T getKey() { + return key; + } + + public void setKey(T key) { + this.key = key; + } +} From d6f8ad07f9b7660c0c34d32f2784f0438c4d9dd4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:23:18 +0000 Subject: [PATCH 6/6] Address code review comments - improve imports and comments Co-authored-by: huayanYu <16700837+huayanYu@users.noreply.github.com> --- .../java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java | 3 ++- src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java | 3 ++- .../java/com/github/jsonzou/jmockdata/bean/GeneralBean.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java b/src/main/java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java index 13215f10d..aef73e7e0 100644 --- a/src/main/java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java +++ b/src/main/java/com/github/jsonzou/jmockdata/mocker/BeanMocker.java @@ -11,6 +11,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -55,7 +56,7 @@ public Object mock(DataConfig mockConfig) { TypeVariable[] typeVariables = clazz.getTypeParameters(); if (typeVariables != null && typeVariables.length > 0) { // Save current type variable mappings - savedTypeVariables = new java.util.HashMap<>(); + savedTypeVariables = new HashMap<>(); for (int index = 0; index < Math.min(typeVariables.length, genericTypes.length); index++) { String varName = typeVariables[index].getName(); Type oldValue = mockConfig.globalConfig().getVariableType(varName); diff --git a/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java b/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java index 8b33c3cea..5b05b692e 100644 --- a/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java +++ b/src/test/java/com/github/jsonzou/jmockdata/JMockDataTest.java @@ -122,7 +122,8 @@ public void testGenericData() { } /** - * Test for issue: 普通对象包含含有泛型字段的集合时mock失败 + * Test for issue: Mocking fails when regular objects contain collections with generic fields + * (普通对象包含含有泛型字段的集合时mock失败) * Test mocking a bean with a field containing a parameterized generic type */ @Test diff --git a/src/test/java/com/github/jsonzou/jmockdata/bean/GeneralBean.java b/src/test/java/com/github/jsonzou/jmockdata/bean/GeneralBean.java index c0098fdfb..223dcdda2 100644 --- a/src/test/java/com/github/jsonzou/jmockdata/bean/GeneralBean.java +++ b/src/test/java/com/github/jsonzou/jmockdata/bean/GeneralBean.java @@ -4,7 +4,7 @@ /** * Bean containing a list of generic entities - * Used to test the fix for issue: 普通对象包含含有泛型字段的集合时mock失败 + * Used to test the fix for issue: Mocking fails when regular objects contain collections with generic fields */ public class GeneralBean { private List> rows;