Skip to content

Commit f0f01c3

Browse files
authored
Fix serializable check & Add test cases (#12054)
* Add test cases * Fix uts * Add fj2 test * save * Fix check * Disable some test cases * Fix test
1 parent e3e7ce8 commit f0f01c3

File tree

23 files changed

+1973
-48
lines changed

23 files changed

+1973
-48
lines changed

dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -74,20 +74,20 @@ public class ClassUtils {
7474
* @since 2.7.6
7575
*/
7676
public static final Set<Class<?>> SIMPLE_TYPES = ofSet(
77-
Void.class,
78-
Boolean.class,
79-
Character.class,
80-
Byte.class,
81-
Short.class,
82-
Integer.class,
83-
Long.class,
84-
Float.class,
85-
Double.class,
86-
String.class,
87-
BigDecimal.class,
88-
BigInteger.class,
89-
Date.class,
90-
Object.class
77+
Void.class,
78+
Boolean.class,
79+
Character.class,
80+
Byte.class,
81+
Short.class,
82+
Integer.class,
83+
Long.class,
84+
Float.class,
85+
Double.class,
86+
String.class,
87+
BigDecimal.class,
88+
BigInteger.class,
89+
Date.class,
90+
Object.class
9191
);
9292
/**
9393
* Prefix for internal array class names: "[L"
@@ -118,8 +118,8 @@ public class ClassUtils {
118118
Set<Class<?>> primitiveTypeNames = new HashSet<>(32);
119119
primitiveTypeNames.addAll(PRIMITIVE_WRAPPER_TYPE_MAP.values());
120120
primitiveTypeNames.addAll(Arrays
121-
.asList(boolean[].class, byte[].class, char[].class, double[].class,
122-
float[].class, int[].class, long[].class, short[].class));
121+
.asList(boolean[].class, byte[].class, char[].class, double[].class,
122+
float[].class, int[].class, long[].class, short[].class));
123123
for (Class<?> primitiveTypeName : primitiveTypeNames) {
124124
PRIMITIVE_TYPE_NAME_MAP.put(primitiveTypeName.getName(), primitiveTypeName);
125125
}
@@ -137,12 +137,12 @@ public class ClassUtils {
137137
private static final char PACKAGE_SEPARATOR_CHAR = '.';
138138

139139
public static Class<?> forNameWithThreadContextClassLoader(String name)
140-
throws ClassNotFoundException {
140+
throws ClassNotFoundException {
141141
return forName(name, Thread.currentThread().getContextClassLoader());
142142
}
143143

144144
public static Class<?> forNameWithCallerClassLoader(String name, Class<?> caller)
145-
throws ClassNotFoundException {
145+
throws ClassNotFoundException {
146146
return forName(name, caller.getClassLoader());
147147
}
148148

@@ -224,7 +224,7 @@ public static Class<?> forName(String name) throws ClassNotFoundException {
224224
* @see Class#forName(String, boolean, ClassLoader)
225225
*/
226226
public static Class<?> forName(String name, ClassLoader classLoader)
227-
throws ClassNotFoundException, LinkageError {
227+
throws ClassNotFoundException, LinkageError {
228228

229229
Class<?> clazz = resolvePrimitiveClassName(name);
230230
if (clazz != null) {
@@ -244,7 +244,7 @@ public static Class<?> forName(String name, ClassLoader classLoader)
244244
String elementClassName = null;
245245
if (internalArrayMarker == 0) {
246246
elementClassName = name
247-
.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);
247+
.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);
248248
} else if (name.startsWith("[")) {
249249
elementClassName = name.substring(1);
250250
}
@@ -354,7 +354,7 @@ public static Object convertPrimitive(FrameworkModel frameworkModel, Class<?> ty
354354
*/
355355
public static boolean isTypeMatch(Class<?> type, String value) {
356356
if ((type == boolean.class || type == Boolean.class)
357-
&& !("true".equals(value) || "false".equals(value))) {
357+
&& !("true".equals(value) || "false".equals(value))) {
358358
return false;
359359
}
360360
return true;
@@ -408,18 +408,18 @@ public static Set<Class<?>> getAllInterfaces(Class<?> type, Predicate<Class<?>>.
408408
if (isNotEmpty(interfaces)) {
409409
// add current interfaces
410410
Arrays.stream(interfaces)
411-
.filter(resolved::add)
412-
.forEach(cls -> {
413-
allInterfaces.add(cls);
414-
waitResolve.add(cls);
415-
});
411+
.filter(resolved::add)
412+
.forEach(cls -> {
413+
allInterfaces.add(cls);
414+
waitResolve.add(cls);
415+
});
416416
}
417417

418418
// add all super classes to waitResolve
419419
getAllSuperClasses(clazz)
420-
.stream()
421-
.filter(resolved::add)
422-
.forEach(waitResolve::add);
420+
.stream()
421+
.filter(resolved::add)
422+
.forEach(waitResolve::add);
423423

424424
clazz = waitResolve.poll();
425425
}
@@ -535,7 +535,7 @@ public static String[] getMethodNames(Class<?> tClass) {
535535
}
536536
Method[] methods = Arrays.stream(tClass.getMethods())
537537
.collect(Collectors.toList())
538-
.toArray(new Method[] {});
538+
.toArray(new Method[]{});
539539
List<String> mns = new ArrayList<>(); // method names.
540540
boolean hasMethod = hasMethods(methods);
541541
if (hasMethod) {
@@ -551,6 +551,44 @@ public static String[] getMethodNames(Class<?> tClass) {
551551
return mns.toArray(new String[0]);
552552
}
553553

554+
public static boolean isMatch(Class<?> from, Class<?> to) {
555+
if (from == to) {
556+
return true;
557+
}
558+
boolean isMatch;
559+
if (from.isPrimitive()) {
560+
isMatch = matchPrimitive(from, to);
561+
} else if (to.isPrimitive()) {
562+
isMatch = matchPrimitive(to, from);
563+
} else {
564+
isMatch = to.isAssignableFrom(from);
565+
}
566+
return isMatch;
567+
}
568+
569+
private static boolean matchPrimitive(Class<?> from, Class<?> to) {
570+
if (from == boolean.class) {
571+
return to == Boolean.class;
572+
} else if (from == byte.class) {
573+
return to == Byte.class;
574+
} else if (from == char.class) {
575+
return to == Character.class;
576+
} else if (from == short.class) {
577+
return to == Short.class;
578+
} else if (from == int.class) {
579+
return to == Integer.class;
580+
} else if (from == long.class) {
581+
return to == Long.class;
582+
} else if (from == float.class) {
583+
return to == Float.class;
584+
} else if (from == double.class) {
585+
return to == Double.class;
586+
} else if (from == void.class) {
587+
return to == Void.class;
588+
}
589+
return false;
590+
}
591+
554592
/**
555593
* get method name array.
556594
*
@@ -562,7 +600,7 @@ public static String[] getDeclaredMethodNames(Class<?> tClass) {
562600
}
563601
Method[] methods = Arrays.stream(tClass.getMethods())
564602
.collect(Collectors.toList())
565-
.toArray(new Method[] {});
603+
.toArray(new Method[]{});
566604
List<String> dmns = new ArrayList<>(); // method names.
567605
boolean hasMethod = hasMethods(methods);
568606
if (hasMethod) {

dubbo-dependencies-bom/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
<httpclient_version>4.5.13</httpclient_version>
101101
<httpcore_version>4.4.6</httpcore_version>
102102
<fastjson_version>1.2.83</fastjson_version>
103-
<fastjson2_version>2.0.23</fastjson2_version>
103+
<fastjson2_version>2.0.27</fastjson2_version>
104104
<zookeeper_version>3.4.14</zookeeper_version>
105105
<curator_version>4.2.0</curator_version>
106106
<curator_test_version>2.12.0</curator_test_version>

dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/codec/ExchangeCodec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ protected void encodeData(ObjectOutput out, Object data) throws IOException {
414414
}
415415

416416
private void encodeEventData(ObjectOutput out, Object data) throws IOException {
417-
out.writeEvent(data);
417+
out.writeEvent((String) data);
418418
}
419419

420420
@Deprecated

dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/codec/ExchangeCodecTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
import org.junit.jupiter.api.Assertions;
3939
import org.junit.jupiter.api.BeforeEach;
40+
import org.junit.jupiter.api.Disabled;
4041
import org.junit.jupiter.api.Test;
4142
import org.mockito.Mockito;
4243

@@ -261,6 +262,7 @@ public void test_Decode_Return_Response_Error() throws IOException {
261262
}
262263

263264
@Test
265+
@Disabled("Event should not be object.")
264266
void test_Decode_Return_Request_Event_Object() throws IOException {
265267
//|10011111|20-stats=ok|id=0|length=0
266268
byte[] header = new byte[]{MAGIC_HIGH, MAGIC_LOW, (byte) (SERIALIZATION_BYTE | (byte) 0xe0), 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -306,6 +308,7 @@ void test_Decode_Return_Request_Heartbeat_Object() throws IOException {
306308
}
307309

308310
@Test
311+
@Disabled("Event should not be object.")
309312
void test_Decode_Return_Request_Object() throws IOException {
310313
//|10011111|20-stats=ok|id=0|length=0
311314
byte[] header = new byte[]{MAGIC_HIGH, MAGIC_LOW, (byte) (SERIALIZATION_BYTE | (byte) 0xe0), 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -393,6 +396,7 @@ void test_Encode_Request() throws IOException {
393396
}
394397

395398
@Test
399+
@Disabled("Event should not be object.")
396400
void test_Encode_Response() throws IOException {
397401
DefaultFuture future = DefaultFuture.newFuture(Mockito.mock(Channel.class), new Request(1001), 100000, null);
398402

dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/ObjectInput.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ default Throwable readThrowable() throws IOException, ClassNotFoundException {
7878
return (Throwable) obj;
7979
}
8080

81-
default Object readEvent() throws IOException, ClassNotFoundException {
82-
return readObject();
81+
default String readEvent() throws IOException, ClassNotFoundException {
82+
return readUTF();
8383
}
8484

8585
default Map<String, Object> readAttachments() throws IOException, ClassNotFoundException {

dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/ObjectOutput.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ public interface ObjectOutput extends DataOutput {
4545
* restricting the content of headers / attachments to Ascii strings and uses ISO_8859_1 to encode them.
4646
* https://tools.ietf.org/html/rfc7540#section-8.1.2
4747
*/
48-
default void writeThrowable(Object obj) throws IOException {
48+
default void writeThrowable(Throwable obj) throws IOException {
4949
writeObject(obj);
5050
}
5151

52-
default void writeEvent(Object data) throws IOException {
52+
default void writeEvent(String data) throws IOException {
5353
writeObject(data);
5454
}
5555

dubbo-serialization/dubbo-serialization-fastjson2/pom.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,4 @@ limitations under the License.
4545
<artifactId>fastjson2</artifactId>
4646
</dependency>
4747
</dependencies>
48-
4948
</project>

dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/FastJson2ObjectInput.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@
1616
*/
1717
package org.apache.dubbo.common.serialize.fastjson2;
1818

19-
import java.io.IOException;
20-
import java.io.InputStream;
21-
import java.lang.reflect.Type;
22-
2319
import org.apache.dubbo.common.serialize.ObjectInput;
20+
import org.apache.dubbo.common.utils.ClassUtils;
2421

2522
import com.alibaba.fastjson2.JSONB;
2623
import com.alibaba.fastjson2.JSONReader;
2724

25+
import java.io.IOException;
26+
import java.io.InputStream;
27+
import java.lang.reflect.Type;
28+
2829
/**
2930
* FastJson object input implementation
3031
*/
@@ -112,22 +113,28 @@ public <T> T readObject(Class<T> cls) throws IOException {
112113
throw new IllegalArgumentException("deserialize failed. expected read length: " + length + " but actual read: " + read);
113114
}
114115
Fastjson2SecurityManager.Handler securityFilter = fastjson2SecurityManager.getSecurityFilter();
116+
T result;
115117
if (securityFilter.isCheckSerializable()) {
116-
return (T) JSONB.parseObject(bytes, Object.class, securityFilter,
118+
result = JSONB.parseObject(bytes, cls, securityFilter,
117119
JSONReader.Feature.UseDefaultConstructorAsPossible,
118120
JSONReader.Feature.ErrorOnNoneSerializable,
121+
JSONReader.Feature.IgnoreAutoTypeNotMatch,
119122
JSONReader.Feature.UseNativeObject,
120123
JSONReader.Feature.FieldBased);
121124
} else {
122-
return (T) JSONB.parseObject(bytes, Object.class, securityFilter,
125+
result = JSONB.parseObject(bytes, cls, securityFilter,
123126
JSONReader.Feature.UseDefaultConstructorAsPossible,
124127
JSONReader.Feature.UseNativeObject,
128+
JSONReader.Feature.IgnoreAutoTypeNotMatch,
125129
JSONReader.Feature.FieldBased);
126130
}
131+
if (result != null && cls != null && !ClassUtils.isMatch(result.getClass(), cls)) {
132+
throw new IllegalArgumentException("deserialize failed. expected class: " + cls + " but actual class: " + result.getClass());
133+
}
134+
return result;
127135
}
128136

129137
@Override
130-
@SuppressWarnings("unchecked")
131138
public <T> T readObject(Class<T> cls, Type type) throws IOException, ClassNotFoundException {
132139
updateClassLoaderIfNeed();
133140
int length = readLength();
@@ -137,18 +144,25 @@ public <T> T readObject(Class<T> cls, Type type) throws IOException, ClassNotFou
137144
throw new IllegalArgumentException("deserialize failed. expected read length: " + length + " but actual read: " + read);
138145
}
139146
Fastjson2SecurityManager.Handler securityFilter = fastjson2SecurityManager.getSecurityFilter();
147+
T result;
140148
if (securityFilter.isCheckSerializable()) {
141-
return (T) JSONB.parseObject(bytes, Object.class, securityFilter,
149+
result = JSONB.parseObject(bytes, cls, securityFilter,
142150
JSONReader.Feature.UseDefaultConstructorAsPossible,
143151
JSONReader.Feature.ErrorOnNoneSerializable,
152+
JSONReader.Feature.IgnoreAutoTypeNotMatch,
144153
JSONReader.Feature.UseNativeObject,
145154
JSONReader.Feature.FieldBased);
146155
} else {
147-
return (T) JSONB.parseObject(bytes, Object.class, securityFilter,
156+
result = JSONB.parseObject(bytes, cls, securityFilter,
148157
JSONReader.Feature.UseDefaultConstructorAsPossible,
149158
JSONReader.Feature.UseNativeObject,
159+
JSONReader.Feature.IgnoreAutoTypeNotMatch,
150160
JSONReader.Feature.FieldBased);
151161
}
162+
if (result != null && cls != null && !ClassUtils.isMatch(result.getClass(), cls)) {
163+
throw new IllegalArgumentException("deserialize failed. expected class: " + cls + " but actual class: " + result.getClass());
164+
}
165+
return result;
152166
}
153167

154168
private void updateClassLoaderIfNeed() {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.example.test;
18+
19+
import java.io.Serializable;
20+
import java.util.Objects;
21+
22+
public class TestPojo implements Serializable {
23+
private final String data;
24+
25+
public TestPojo(String data) {
26+
this.data = data;
27+
}
28+
29+
@Override
30+
public String toString() {
31+
throw new IllegalAccessError();
32+
}
33+
34+
@Override
35+
public boolean equals(Object o) {
36+
if (this == o) return true;
37+
if (o == null || getClass() != o.getClass()) return false;
38+
TestPojo testPojo = (TestPojo) o;
39+
return Objects.equals(data, testPojo.data);
40+
}
41+
42+
@Override
43+
public int hashCode() {
44+
return Objects.hash(data);
45+
}
46+
}

0 commit comments

Comments
 (0)