Skip to content

Commit 7314250

Browse files
authored
fix(java): raise exception when registering invalid serializer for Map/List (#2291)
## What does this PR do? raise an exception with error message when when registering serializer for Map/List. ## Related issues - #2251 - #2270 ## Does this PR introduce any user-facing change? - [ ] Does this PR introduce any public API change? - [ ] Does this PR introduce any binary protocol compatibility change? ## Benchmark
1 parent bb5117e commit 7314250

File tree

4 files changed

+236
-1
lines changed

4 files changed

+236
-1
lines changed

java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
import org.apache.fory.serializer.OptionalSerializers;
136136
import org.apache.fory.serializer.PrimitiveSerializers;
137137
import org.apache.fory.serializer.ReplaceResolveSerializer;
138+
import org.apache.fory.serializer.SerializationUtils;
138139
import org.apache.fory.serializer.Serializer;
139140
import org.apache.fory.serializer.SerializerFactory;
140141
import org.apache.fory.serializer.Serializers;
@@ -737,6 +738,9 @@ public <T> void registerSerializer(Class<T> type, Class<? extends Serializer> se
737738
* @param serializer serializer for object of {@code type}
738739
*/
739740
public void registerSerializer(Class<?> type, Serializer<?> serializer) {
741+
if (!serializer.getClass().getPackage().getName().startsWith("org.apache.fory")) {
742+
SerializationUtils.validate(type, serializer.getClass());
743+
}
740744
if (!extRegistry.registeredClassIdMap.containsKey(type) && !fory.isCrossLanguage()) {
741745
register(type);
742746
}

java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import org.apache.fory.serializer.NonexistentClass;
7272
import org.apache.fory.serializer.NonexistentClassSerializers;
7373
import org.apache.fory.serializer.ObjectSerializer;
74+
import org.apache.fory.serializer.SerializationUtils;
7475
import org.apache.fory.serializer.Serializer;
7576
import org.apache.fory.serializer.Serializers;
7677
import org.apache.fory.serializer.collection.AbstractCollectionSerializer;
@@ -272,11 +273,17 @@ private ClassInfo newClassInfo(
272273

273274
public <T> void registerSerializer(Class<T> type, Class<? extends Serializer> serializerClass) {
274275
ClassInfo classInfo = checkClassRegistration(type);
276+
if (!serializerClass.getPackage().getName().startsWith("org.apache.fory")) {
277+
SerializationUtils.validate(type, serializerClass);
278+
}
275279
classInfo.serializer = Serializers.newSerializer(fory, type, serializerClass);
276280
}
277281

278282
public void registerSerializer(Class<?> type, Serializer<?> serializer) {
279283
ClassInfo classInfo = checkClassRegistration(type);
284+
if (!serializer.getClass().getPackage().getName().startsWith("org.apache.fory")) {
285+
SerializationUtils.validate(type, serializer.getClass());
286+
}
280287
classInfo.serializer = serializer;
281288
}
282289

java/fory-core/src/main/java/org/apache/fory/serializer/SerializationUtils.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,47 @@
1919

2020
package org.apache.fory.serializer;
2121

22+
import java.util.Collection;
23+
import java.util.Map;
2224
import org.apache.fory.Fory;
2325
import org.apache.fory.annotation.Internal;
2426
import org.apache.fory.resolver.ClassInfo;
2527
import org.apache.fory.resolver.TypeResolver;
28+
import org.apache.fory.serializer.collection.AbstractCollectionSerializer;
29+
import org.apache.fory.serializer.collection.AbstractMapSerializer;
2630

2731
@Internal
28-
class SerializationUtils {
32+
public class SerializationUtils {
2933
public static TypeResolver getTypeResolver(Fory fory) {
3034
return fory.isCrossLanguage() ? fory.getXtypeResolver() : fory.getClassResolver();
3135
}
3236

3337
public static ClassInfo getClassInfo(Fory fory, Class<?> cls) {
3438
return getTypeResolver(fory).getClassInfo(cls);
3539
}
40+
41+
public static void validateSerializer(
42+
Class<?> type,
43+
Class<? extends Serializer> serializerClass,
44+
Class<?> parentType,
45+
Class<?> requiredSerializerBase) {
46+
if (!parentType.isAssignableFrom(type)) {
47+
return;
48+
}
49+
boolean valid = requiredSerializerBase.isAssignableFrom(serializerClass);
50+
if (!valid) {
51+
throw new IllegalArgumentException(
52+
"Serializer for type "
53+
+ type.getName()
54+
+ " must extend "
55+
+ requiredSerializerBase.getSimpleName()
56+
+ ", but got "
57+
+ serializerClass.getName());
58+
}
59+
}
60+
61+
public static void validate(Class<?> type, Class<? extends Serializer> serializerClass) {
62+
validateSerializer(type, serializerClass, Collection.class, AbstractCollectionSerializer.class);
63+
validateSerializer(type, serializerClass, Map.class, AbstractMapSerializer.class);
64+
}
3665
}
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package javax.fory.test;
21+
22+
import static org.testng.Assert.assertThrows;
23+
import static org.testng.Assert.assertTrue;
24+
25+
import java.util.AbstractList;
26+
import java.util.AbstractMap;
27+
import java.util.Collection;
28+
import java.util.Collections;
29+
import java.util.Map;
30+
import java.util.Set;
31+
import org.apache.fory.Fory;
32+
import org.apache.fory.memory.MemoryBuffer;
33+
import org.apache.fory.serializer.Serializer;
34+
import org.apache.fory.serializer.collection.AbstractCollectionSerializer;
35+
import org.apache.fory.serializer.collection.AbstractMapSerializer;
36+
import org.testng.annotations.Test;
37+
38+
public class ResolverValidateSerializerTest {
39+
static final class InvalidList extends AbstractList<Object> {
40+
@Override
41+
public Object get(int index) {
42+
throw new IndexOutOfBoundsException();
43+
}
44+
45+
@Override
46+
public int size() {
47+
return 0;
48+
}
49+
50+
public static final class InvalidListSerializer extends Serializer<InvalidList> {
51+
public InvalidListSerializer(Fory fory) {
52+
super(fory, InvalidList.class);
53+
}
54+
55+
@Override
56+
public void write(MemoryBuffer buffer, InvalidList value) {
57+
// no-op
58+
}
59+
60+
@Override
61+
public InvalidList read(MemoryBuffer buffer) {
62+
return new InvalidList();
63+
}
64+
}
65+
}
66+
67+
static final class ValidList extends AbstractList<Object> {
68+
@Override
69+
public Object get(int index) {
70+
throw new IndexOutOfBoundsException();
71+
}
72+
73+
@Override
74+
public int size() {
75+
return 0;
76+
}
77+
78+
public static final class ValidListSerializer extends AbstractCollectionSerializer<ValidList> {
79+
public ValidListSerializer(Fory fory) {
80+
super(fory, ValidList.class);
81+
}
82+
83+
@Override
84+
public Collection<?> onCollectionWrite(MemoryBuffer buffer, ValidList value) {
85+
return Collections.emptyList();
86+
}
87+
88+
@Override
89+
public ValidList read(MemoryBuffer buffer) {
90+
return onCollectionRead(Collections.emptyList());
91+
}
92+
93+
@Override
94+
public ValidList onCollectionRead(Collection collection) {
95+
return new ValidList();
96+
}
97+
}
98+
}
99+
100+
static final class InvalidMap extends AbstractMap<Object, Object> {
101+
@Override
102+
public Set<Entry<Object, Object>> entrySet() {
103+
return Collections.emptySet();
104+
}
105+
106+
public static final class InvalidMapSerializer extends Serializer<InvalidMap> {
107+
public InvalidMapSerializer(Fory fory) {
108+
super(fory, InvalidMap.class);
109+
}
110+
111+
@Override
112+
public void write(MemoryBuffer buffer, InvalidMap value) {
113+
// no-op
114+
}
115+
116+
@Override
117+
public InvalidMap read(MemoryBuffer buffer) {
118+
return new InvalidMap();
119+
}
120+
}
121+
}
122+
123+
static final class ValidMap extends AbstractMap<Object, Object> {
124+
@Override
125+
public Set<Entry<Object, Object>> entrySet() {
126+
return Collections.emptySet();
127+
}
128+
129+
public static final class ValidMapSerializer extends AbstractMapSerializer<ValidMap> {
130+
public ValidMapSerializer(Fory fory) {
131+
super(fory, ValidMap.class);
132+
}
133+
134+
@Override
135+
public Map<?, ?> onMapWrite(MemoryBuffer buffer, ValidMap value) {
136+
return Collections.emptyMap();
137+
}
138+
139+
@Override
140+
public ValidMap onMapCopy(Map map) {
141+
return new ValidMap();
142+
}
143+
144+
@Override
145+
public ValidMap read(MemoryBuffer buffer) {
146+
return onMapRead(Collections.emptyMap());
147+
}
148+
149+
@Override
150+
public ValidMap onMapRead(Map map) {
151+
return new ValidMap();
152+
}
153+
}
154+
}
155+
156+
@Test
157+
public void testListAndMapSerializerRegistration() {
158+
Fory fory = Fory.builder().withRefTracking(true).requireClassRegistration(false).build();
159+
// List invalid
160+
assertThrows(
161+
IllegalArgumentException.class,
162+
() -> fory.registerSerializer(InvalidList.class, InvalidList.InvalidListSerializer.class));
163+
assertThrows(
164+
IllegalArgumentException.class,
165+
() ->
166+
fory.registerSerializer(
167+
InvalidList.class, new InvalidList.InvalidListSerializer(fory)));
168+
assertThrows(
169+
IllegalArgumentException.class,
170+
() ->
171+
fory.registerSerializer(
172+
InvalidList.class, f -> new InvalidList.InvalidListSerializer(f)));
173+
// List valid
174+
fory.register(ValidList.class);
175+
fory.registerSerializer(ValidList.class, new ValidList.ValidListSerializer(fory));
176+
Object listResult = fory.deserialize(fory.serialize(new ValidList()));
177+
assertTrue(listResult instanceof ValidList);
178+
// Map invalid
179+
assertThrows(
180+
IllegalArgumentException.class,
181+
() -> fory.registerSerializer(InvalidMap.class, InvalidMap.InvalidMapSerializer.class));
182+
assertThrows(
183+
IllegalArgumentException.class,
184+
() -> fory.registerSerializer(InvalidMap.class, new InvalidMap.InvalidMapSerializer(fory)));
185+
assertThrows(
186+
IllegalArgumentException.class,
187+
() ->
188+
fory.registerSerializer(InvalidMap.class, f -> new InvalidMap.InvalidMapSerializer(f)));
189+
// Map valid
190+
fory.register(ValidMap.class);
191+
fory.registerSerializer(ValidMap.class, new ValidMap.ValidMapSerializer(fory));
192+
Object mapResult = fory.deserialize(fory.serialize(new ValidMap()));
193+
assertTrue(mapResult instanceof ValidMap);
194+
}
195+
}

0 commit comments

Comments
 (0)