Skip to content

Commit 5621a4c

Browse files
committed
improved android support
1 parent 0bbd0d1 commit 5621a4c

13 files changed

+281
-35
lines changed

core/src/main/java/com/alibaba/fastjson2/internal/asm/ASMUtils.java

Lines changed: 130 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
import java.lang.reflect.AccessibleObject;
1818
import java.lang.reflect.Constructor;
1919
import java.lang.reflect.Method;
20+
import java.lang.reflect.Modifier;
2021
import java.time.format.DateTimeParseException;
22+
import java.util.Arrays;
2123
import java.util.HashMap;
2224
import java.util.Map;
25+
import java.util.Objects;
2326
import java.util.concurrent.atomic.AtomicReference;
2427
import java.util.function.*;
2528

@@ -78,10 +81,55 @@ public class ASMUtils {
7881
public static final String DESC_SUPPLIER = "Ljava/util/function/Supplier;";
7982
public static final String DESC_JSONSCHEMA = 'L' + JSONSchema.class.getName().replace('.', '/') + ';';
8083

84+
static final Map<MethodInfo, String[]> paramMapping = new HashMap<>();
85+
8186
static Map<Class, String> descMapping = new HashMap<>();
8287
static Map<Class, String> typeMapping = new HashMap<>();
8388

8489
static {
90+
paramMapping.put(
91+
new MethodInfo(
92+
"com.alibaba.fastjson2.util.ParameterizedTypeImpl",
93+
"<init>",
94+
new String[]{"[Ljava.lang.reflect.Type;", "java.lang.reflect.Type", "java.lang.reflect.Type"}
95+
),
96+
new String[]{"actualTypeArguments", "ownerType", "rawType"}
97+
);
98+
99+
paramMapping.put(
100+
new MethodInfo(
101+
"org.apache.commons.lang3.tuple.Triple",
102+
"of",
103+
new String[]{"java.lang.Object", "java.lang.Object", "java.lang.Object"}
104+
),
105+
new String[]{"left", "middle", "right"}
106+
);
107+
paramMapping.put(
108+
new MethodInfo(
109+
"org.apache.commons.lang3.tuple.MutableTriple",
110+
"<init>",
111+
new String[]{"java.lang.Object", "java.lang.Object", "java.lang.Object"}
112+
),
113+
new String[]{"left", "middle", "right"}
114+
);
115+
116+
paramMapping.put(
117+
new MethodInfo(
118+
"org.javamoney.moneta.Money",
119+
"<init>",
120+
new String[]{"java.math.BigDecimal", "javax.money.CurrencyUnit", "javax.money.MonetaryContext"}
121+
),
122+
new String[]{"number", "currency", "monetaryContext"}
123+
);
124+
paramMapping.put(
125+
new MethodInfo(
126+
"org.javamoney.moneta.Money",
127+
"<init>",
128+
new String[]{"java.math.BigDecimal", "javax.money.CurrencyUnit"}
129+
),
130+
new String[]{"number", "currency"}
131+
);
132+
85133
descMapping.put(int.class, "I");
86134
descMapping.put(void.class, "V");
87135
descMapping.put(boolean.class, "Z");
@@ -279,6 +327,11 @@ public static String[] lookupParameterNames(AccessibleObject methodOrCtor) {
279327
return new String[paramCount];
280328
}
281329

330+
String[] paramNames = paramMapping.get(new MethodInfo(declaringClass.getName(), name, types));
331+
if (paramNames != null) {
332+
return paramNames;
333+
}
334+
282335
ClassLoader classLoader = declaringClass.getClassLoader();
283336
if (classLoader == null) {
284337
classLoader = ClassLoader.getSystemClassLoader();
@@ -288,30 +341,86 @@ public static String[] lookupParameterNames(AccessibleObject methodOrCtor) {
288341
String resourceName = className.replace('.', '/') + ".class";
289342
InputStream is = classLoader.getResourceAsStream(resourceName);
290343

291-
if (is == null) {
292-
return new String[paramCount];
344+
if (is != null) {
345+
try {
346+
ClassReader reader = new ClassReader(is);
347+
TypeCollector visitor = new TypeCollector(name, types);
348+
reader.accept(visitor);
349+
350+
paramNames = visitor.getParameterNamesForMethod();
351+
if (paramNames != null && paramNames.length == paramCount - 1) {
352+
Class<?> dd = declaringClass.getDeclaringClass();
353+
if (dd != null && dd.equals(types[0])) {
354+
String[] strings = new String[paramCount];
355+
strings[0] = "this$0";
356+
System.arraycopy(paramNames, 0, strings, 1, paramNames.length);
357+
paramNames = strings;
358+
}
359+
}
360+
return paramNames;
361+
} catch (IOException ignored) {
362+
// ignored
363+
} finally {
364+
IOUtils.close(is);
365+
}
293366
}
294367

295-
try {
296-
ClassReader reader = new ClassReader(is);
297-
TypeCollector visitor = new TypeCollector(name, types);
298-
reader.accept(visitor);
299-
300-
String[] params = visitor.getParameterNamesForMethod();
301-
if (params != null && params.length == paramCount - 1) {
302-
Class<?> dd = declaringClass.getDeclaringClass();
303-
if (dd != null && dd.equals(types[0])) {
304-
String[] strings = new String[paramCount];
305-
strings[0] = "this$0";
306-
System.arraycopy(params, 0, strings, 1, params.length);
307-
params = strings;
308-
}
368+
paramNames = new String[paramCount];
369+
int i;
370+
if (types[0] == declaringClass.getDeclaringClass()
371+
&& !Modifier.isStatic(declaringClass.getModifiers())) {
372+
paramNames[0] = "this.$0";
373+
i = 1;
374+
} else {
375+
i = 0;
376+
}
377+
for (; i < paramNames.length; i++) {
378+
paramNames[i] = "arg" + i;
379+
}
380+
return paramNames;
381+
}
382+
383+
static class MethodInfo {
384+
final String className;
385+
final String methodName;
386+
final String[] paramTypeNames;
387+
int hash;
388+
389+
public MethodInfo(String className, String methodName, String[] paramTypeNames) {
390+
this.className = className;
391+
this.methodName = methodName;
392+
this.paramTypeNames = paramTypeNames;
393+
}
394+
395+
public MethodInfo(String className, String methodName, Class[] paramTypes) {
396+
this.className = className;
397+
this.methodName = methodName;
398+
this.paramTypeNames = new String[paramTypes.length];
399+
for (int i = 0; i < paramTypes.length; i++) {
400+
paramTypeNames[i] = paramTypes[i].getName();
309401
}
310-
return params;
311-
} catch (IOException e) {
312-
return new String[paramCount];
313-
} finally {
314-
IOUtils.close(is);
402+
}
403+
404+
@Override
405+
public boolean equals(Object o) {
406+
if (this == o) {
407+
return true;
408+
}
409+
if (o == null || getClass() != o.getClass()) {
410+
return false;
411+
}
412+
MethodInfo that = (MethodInfo) o;
413+
return Objects.equals(className, that.className) && Objects.equals(methodName, that.methodName) && Arrays.equals(paramTypeNames, that.paramTypeNames);
414+
}
415+
416+
@Override
417+
public int hashCode() {
418+
if (hash == 0) {
419+
int result = Objects.hash(className, methodName);
420+
result = 31 * result + Arrays.hashCode(paramTypeNames);
421+
hash = result;
422+
}
423+
return hash;
315424
}
316425
}
317426
}

core/src/main/java/com/alibaba/fastjson2/reader/ConstructorFunction.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.alibaba.fastjson2.reader;
22

33
import com.alibaba.fastjson2.JSONException;
4+
import com.alibaba.fastjson2.JSONFactory;
5+
import com.alibaba.fastjson2.codec.FieldInfo;
46
import com.alibaba.fastjson2.internal.asm.ASMUtils;
57
import com.alibaba.fastjson2.util.Fnv;
68
import com.alibaba.fastjson2.util.TypeUtils;
@@ -68,6 +70,20 @@ final class ConstructorFunction<T>
6870
alternateConstructor.setAccessible(true);
6971

7072
String[] parameterNames = ASMUtils.lookupParameterNames(alternateConstructor);
73+
74+
Parameter[] parameters = alternateConstructor.getParameters();
75+
FieldInfo fieldInfo = new FieldInfo();
76+
ObjectReaderProvider provider = JSONFactory.getDefaultObjectReaderProvider();
77+
for (int i = 0; i < parameters.length && i < parameterNames.length; i++) {
78+
fieldInfo.init();
79+
80+
Parameter parameter = parameters[i];
81+
provider.getFieldInfo(fieldInfo, alternateConstructor.getDeclaringClass(), alternateConstructor, i, parameter);
82+
if (fieldInfo.fieldName != null) {
83+
parameterNames[i] = fieldInfo.fieldName;
84+
}
85+
}
86+
7187
long[] parameterNameHashCodes = new long[parameterNames.length];
7288
Type[] parameterTypes = alternateConstructor.getGenericParameterTypes();
7389
Set<Long> paramHashCodes = new HashSet<>(parameterNames.length);

core/src/main/java/com/alibaba/fastjson2/reader/FieldReaderDoubleField.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ public void readFieldValue(JSONReader jsonReader, T object) {
3030
schema.assertValidate(fieldValue);
3131
}
3232

33+
if (fieldValue == null && defaultValue != null) {
34+
return;
35+
}
36+
3337
try {
3438
field.set(object, fieldValue);
3539
} catch (Exception e) {

core/src/main/java/com/alibaba/fastjson2/reader/FieldReaderDoubleFunc.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ public void readFieldValue(JSONReader jsonReader, T object) {
5252
}
5353
}
5454

55+
if (fieldValue == null && defaultValue != null) {
56+
return;
57+
}
58+
5559
if (schema != null) {
5660
schema.assertValidate(fieldValue);
5761
}

core/src/main/java/com/alibaba/fastjson2/reader/FieldReaderDoubleMethod.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public void readFieldValue(JSONReader jsonReader, T object) {
2929
schema.assertValidate(fieldValue);
3030
}
3131

32+
if (fieldValue == null && defaultValue != null) {
33+
return;
34+
}
35+
3236
try {
3337
method.invoke(object, fieldValue);
3438
} catch (Exception e) {

core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderBaseModule.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -668,14 +668,28 @@ public void getFieldInfo(
668668
}
669669
}
670670

671+
boolean staticClass = Modifier.isStatic(constructor.getDeclaringClass().getModifiers());
671672
Annotation[] annotations = null;
672-
try {
673-
annotations = getAnnotations(parameter);
674-
} catch (ArrayIndexOutOfBoundsException ignored) {
675-
// ignored
673+
if (staticClass) {
674+
try {
675+
annotations = getAnnotations(parameter);
676+
} catch (ArrayIndexOutOfBoundsException ignored) {
677+
// ignored
678+
}
679+
} else {
680+
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
681+
int paIndex;
682+
if (parameterAnnotations.length == constructor.getParameterCount()) {
683+
paIndex = paramIndex;
684+
} else {
685+
paIndex = paramIndex - 1;
686+
}
687+
if (paIndex >= 0 && paIndex < parameterAnnotations.length) {
688+
annotations = parameterAnnotations[paIndex];
689+
}
676690
}
677691

678-
if (annotations != null) {
692+
if (annotations != null && annotations.length > 0) {
679693
processAnnotation(fieldInfo, annotations);
680694
}
681695
}

core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderCreator.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,19 @@ boolean record = BeanUtils.isRecord(objectClass);
10191019

10201020
if (parameterNames == null || parameterNames.length == 0) {
10211021
parameterNames = ASMUtils.lookupParameterNames(creatorConstructor);
1022+
1023+
Parameter[] parameters = creatorConstructor.getParameters();
1024+
FieldInfo fieldInfo = new FieldInfo();
1025+
for (int i = 0; i < parameters.length && i < parameterNames.length; i++) {
1026+
fieldInfo.init();
1027+
1028+
Parameter parameter = parameters[i];
1029+
1030+
provider.getFieldInfo(fieldInfo, objectClass, creatorConstructor, i, parameter);
1031+
if (fieldInfo.fieldName != null) {
1032+
parameterNames[i] = fieldInfo.fieldName;
1033+
}
1034+
}
10221035
}
10231036

10241037
int matchCount = 0;

core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderException.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package com.alibaba.fastjson2.reader;
22

3-
import com.alibaba.fastjson2.JSONB;
4-
import com.alibaba.fastjson2.JSONException;
5-
import com.alibaba.fastjson2.JSONPath;
6-
import com.alibaba.fastjson2.JSONReader;
3+
import com.alibaba.fastjson2.*;
4+
import com.alibaba.fastjson2.codec.FieldInfo;
75
import com.alibaba.fastjson2.internal.asm.ASMUtils;
86
import com.alibaba.fastjson2.util.BeanUtils;
97
import com.alibaba.fastjson2.util.Fnv;
108

119
import java.lang.reflect.Constructor;
10+
import java.lang.reflect.Parameter;
1211
import java.lang.reflect.Type;
1312
import java.time.format.DateTimeParseException;
1413
import java.util.*;
@@ -104,7 +103,22 @@ protected ObjectReaderException(
104103
String[] parameterNames = null;
105104
if (paramCount > 0) {
106105
parameterNames = ASMUtils.lookupParameterNames(constructor);
106+
107+
Parameter[] parameters = constructor.getParameters();
108+
FieldInfo fieldInfo = new FieldInfo();
109+
for (int i = 0; i < parameters.length && i < parameterNames.length; i++) {
110+
fieldInfo.init();
111+
112+
Parameter parameter = parameters[i];
113+
114+
ObjectReaderProvider provider = JSONFactory.getDefaultObjectReaderProvider();
115+
provider.getFieldInfo(fieldInfo, objectClass, constructor, i, parameter);
116+
if (fieldInfo.fieldName != null) {
117+
parameterNames[i] = fieldInfo.fieldName;
118+
}
119+
}
107120
}
121+
108122
constructorParameters.add(parameterNames);
109123
}
110124

core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderImplListStr.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.alibaba.fastjson2.JSONArray;
55
import com.alibaba.fastjson2.JSONException;
66
import com.alibaba.fastjson2.JSONReader;
7+
import com.alibaba.fastjson2.util.GuavaSupport;
78

89
import java.lang.reflect.Type;
910
import java.util.*;
@@ -128,10 +129,29 @@ public Object readJSONBObject(JSONReader jsonReader, Type fieldType, Object fiel
128129
list = new ArrayList();
129130
builder = (Function<Collection, Collection>) ((Collection collection) -> Collections.singletonList(collection.iterator().next()));
130131
} else if (instanceType != null && instanceType != this.listType) {
131-
try {
132-
list = (Collection) instanceType.newInstance();
133-
} catch (InstantiationException | IllegalAccessException e) {
134-
throw new JSONException(jsonReader.info("create instance error " + instanceType), e);
132+
String typeName = instanceType.getTypeName();
133+
switch (typeName) {
134+
case "com.google.common.collect.ImmutableList":
135+
list = new ArrayList();
136+
builder = GuavaSupport.immutableListConverter();
137+
break;
138+
case "com.google.common.collect.ImmutableSet":
139+
list = new ArrayList();
140+
builder = GuavaSupport.immutableSetConverter();
141+
break;
142+
case "com.google.common.collect.Lists$TransformingRandomAccessList":
143+
list = new ArrayList();
144+
break;
145+
case "com.google.common.collect.Lists.TransformingSequentialList":
146+
list = new LinkedList();
147+
break;
148+
default:
149+
try {
150+
list = (Collection) instanceType.newInstance();
151+
} catch (InstantiationException | IllegalAccessException e) {
152+
throw new JSONException(jsonReader.info("create instance error " + instanceType), e);
153+
}
154+
break;
135155
}
136156
} else {
137157
list = (Collection) createInstance(jsonReader.getContext().getFeatures() | features);

0 commit comments

Comments
 (0)