This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fury.git
The following commit(s) were added to refs/heads/main by this push:
new 3cef53c3 fix(java): fix nested map field value serialization by
private map serializer (#1820)
3cef53c3 is described below
commit 3cef53c340efc30dd8e8499e29128eb81212f144
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Aug 28 00:31:43 2024 +0800
fix(java): fix nested map field value serialization by private map
serializer (#1820)
## What does this PR do?
<!-- Describe the purpose of this PR. -->
## Related issues
Closes #1816
## Does this PR introduce any user-facing change?
<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fury/issues/new/choose) describing the
need to do so and update the document if necessary.
-->
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
<!--
When the PR has an impact on performance (if you don't know whether the
PR will have an impact on performance, you can submit the PR first, and
if it will have impact on performance, the code reviewer will explain
it), be sure to attach a benchmark data here.
-->
---
.../fury/builder/BaseObjectCodecBuilder.java | 15 +++
.../java/org/apache/fury/collection/MapEntry.java | 18 ++++
.../serializer/collection/MapSerializersTest.java | 102 +++++++++++++++++++++
3 files changed, 135 insertions(+)
diff --git
a/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java
b/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java
index df7d52e1..8a3315dc 100644
---
a/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java
+++
b/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java
@@ -398,10 +398,18 @@ public abstract class BaseObjectCodecBuilder extends
CodecBuilder {
return visitFury(f ->
f.getClassResolver().isCollection(TypeUtils.getRawType(typeRef)));
}
+ protected boolean useCollectionSerialization(Class<?> type) {
+ return visitFury(f ->
f.getClassResolver().isCollection(TypeUtils.getRawType(type)));
+ }
+
protected boolean useMapSerialization(TypeRef<?> typeRef) {
return visitFury(f ->
f.getClassResolver().isMap(TypeUtils.getRawType(typeRef)));
}
+ protected boolean useMapSerialization(Class<?> type) {
+ return visitFury(f ->
f.getClassResolver().isMap(TypeUtils.getRawType(type)));
+ }
+
/**
* Whether the provided type should be taken as final. Although the
<code>clz</code> can be final,
* the method can still return false. For example, we return false in meta
share mode to write
@@ -491,6 +499,13 @@ public abstract class BaseObjectCodecBuilder extends
CodecBuilder {
serializerClass = Serializer.class;
}
}
+ if (useCollectionSerialization(cls)
+ &&
!AbstractCollectionSerializer.class.isAssignableFrom(serializerClass)) {
+ serializerClass = AbstractCollectionSerializer.class;
+ } else if (useMapSerialization(cls)
+ && !AbstractMapSerializer.class.isAssignableFrom(serializerClass)) {
+ serializerClass = AbstractMapSerializer.class;
+ }
TypeRef<? extends Serializer> serializerTypeRef =
TypeRef.of(serializerClass);
Expression fieldTypeExpr = getClassExpr(cls);
// Don't invoke `Serializer.newSerializer` here, since it(ex.
ObjectSerializer) may set itself
diff --git
a/java/fury-core/src/main/java/org/apache/fury/collection/MapEntry.java
b/java/fury-core/src/main/java/org/apache/fury/collection/MapEntry.java
index bf9ea6ef..b082ba0c 100644
--- a/java/fury-core/src/main/java/org/apache/fury/collection/MapEntry.java
+++ b/java/fury-core/src/main/java/org/apache/fury/collection/MapEntry.java
@@ -20,6 +20,7 @@
package org.apache.fury.collection;
import java.util.Map;
+import java.util.Objects;
/** Map Entry implementation of {@link Map.Entry}. */
public class MapEntry<K, V> implements Map.Entry<K, V> {
@@ -47,4 +48,21 @@ public class MapEntry<K, V> implements Map.Entry<K, V> {
this.value = value;
return o;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MapEntry<?, ?> mapEntry = (MapEntry<?, ?>) o;
+ return Objects.equals(key, mapEntry.key) && Objects.equals(value,
mapEntry.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(key, value);
+ }
}
diff --git
a/java/fury-core/src/test/java/org/apache/fury/serializer/collection/MapSerializersTest.java
b/java/fury-core/src/test/java/org/apache/fury/serializer/collection/MapSerializersTest.java
index 760d061b..74640c68 100644
---
a/java/fury-core/src/test/java/org/apache/fury/serializer/collection/MapSerializersTest.java
+++
b/java/fury-core/src/test/java/org/apache/fury/serializer/collection/MapSerializersTest.java
@@ -38,6 +38,7 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
@@ -503,4 +504,105 @@ public class MapSerializersTest extends FuryTestBase {
copyCheck(fury, map);
}
}
+
+ // must be final class to test nested map value by private MapSerializer
+ private static final class PrivateMap<K, V> implements Map<K, V> {
+ private Set<Entry<K, V>> set = new HashSet<>();
+
+ @Override
+ public int size() {
+ return set.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return set.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return set.stream().anyMatch(e -> e.getKey().equals(key));
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return set.stream().anyMatch(e -> e.getValue().equals(value));
+ }
+
+ @Override
+ public V get(Object key) {
+ for (Entry<K, V> kvEntry : set) {
+ if (kvEntry.getKey().equals(key)) {
+ return kvEntry.getValue();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public V put(K key, V value) {
+ set.add(new MapEntry<>(key, value));
+ return null;
+ }
+
+ @Override
+ public V remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clear() {
+ set.clear();
+ }
+
+ @Override
+ public Set<K> keySet() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Collection<V> values() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ return set;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PrivateMap<?, ?> that = (PrivateMap<?, ?>) o;
+ return Objects.equals(set, that.set);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(set);
+ }
+ }
+
+ @Data
+ @AllArgsConstructor
+ public static class LazyMapCollectionFieldStruct {
+ List<PrivateMap<String, Integer>> mapList;
+ PrivateMap<String, Integer> map;
+ }
+
+ @Test
+ public void testNestedValueByPrivateMapSerializer() {
+ Fury fury = builder().withRefTracking(false).build();
+ // test private map serializer
+ fury.registerSerializer(PrivateMap.class, new MapSerializer(fury,
PrivateMap.class) {});
+ PrivateMap<String, Integer> map = new PrivateMap<>();
+ map.put("k", 1);
+ serDeCheck(fury, new LazyMapCollectionFieldStruct(ofArrayList(map), map));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]