Skip to content

Commit 5379bf3

Browse files
committed
createFunction
1 parent 56bcf12 commit 5379bf3

File tree

5 files changed

+249
-37
lines changed

5 files changed

+249
-37
lines changed

core-jdk11/src/main/java/com/alibaba/fastjson2/introspect/PropertyAccessorFactoryMethodHandle.java

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
import java.lang.reflect.Type;
1414
import java.math.BigDecimal;
1515
import java.math.BigInteger;
16-
import java.util.function.Function;
17-
import java.util.function.Supplier;
16+
import java.util.function.*;
1817

1918
/**
2019
* Property accessor factory that uses MethodHandles.Lookup for field access.
@@ -87,6 +86,60 @@ public Function createFunction(Constructor constructor) {
8786
}
8887
}
8988

89+
@Override
90+
public IntFunction createIntFunction(Constructor constructor) {
91+
try {
92+
MethodHandles.Lookup lookup = lookup(constructor.getDeclaringClass());
93+
MethodHandle methodHandle = lookup.unreflectConstructor(constructor);
94+
return (arg) -> {
95+
try {
96+
return methodHandle.invoke(arg);
97+
} catch (Throwable e) {
98+
throw new RuntimeException(e);
99+
}
100+
};
101+
} catch (Throwable ignored) {
102+
// ignore
103+
return super.createIntFunction(constructor);
104+
}
105+
}
106+
107+
@Override
108+
public LongFunction createLongFunction(Constructor constructor) {
109+
try {
110+
MethodHandles.Lookup lookup = lookup(constructor.getDeclaringClass());
111+
MethodHandle methodHandle = lookup.unreflectConstructor(constructor);
112+
return (arg) -> {
113+
try {
114+
return methodHandle.invoke(arg);
115+
} catch (Throwable e) {
116+
throw new RuntimeException(e);
117+
}
118+
};
119+
} catch (Throwable ignored) {
120+
// ignore
121+
return super.createLongFunction(constructor);
122+
}
123+
}
124+
125+
@Override
126+
public DoubleFunction createDoubleFunction(Constructor constructor) {
127+
try {
128+
MethodHandles.Lookup lookup = lookup(constructor.getDeclaringClass());
129+
MethodHandle methodHandle = lookup.unreflectConstructor(constructor);
130+
return (arg) -> {
131+
try {
132+
return methodHandle.invoke(arg);
133+
} catch (Throwable e) {
134+
throw new RuntimeException(e);
135+
}
136+
};
137+
} catch (Throwable ignored) {
138+
// ignore
139+
return super.createDoubleFunction(constructor);
140+
}
141+
}
142+
90143
/**
91144
* Creates a property accessor for the given field using MethodHandle-based implementation.
92145
* Different accessor implementations are created based on the field type to provide

core-jdk11/src/test/java/com/alibaba/fastjson2/introspect/PropertyAccessorFactoryVarHandleTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ public static class TestClass {
4343
public TestClass() {
4444
}
4545

46+
public TestClass(int intField) {
47+
this.intField = intField;
48+
}
49+
50+
public TestClass(long longField) {
51+
this.longField = longField;
52+
}
53+
54+
public TestClass(double doubleField) {
55+
this.doubleField = doubleField;
56+
}
57+
4658
public TestClass(Byte byteObjField) {
4759
this.byteObjField = byteObjField;
4860
}
@@ -108,6 +120,9 @@ public void allocate(PropertyAccessorFactory factory) throws Exception {
108120
.get());
109121

110122
assertEquals((byte) 50, ((TestClass) factory.createFunction(TestClass.class.getDeclaredConstructor(Byte.class)).apply((byte) 50)).byteObjField);
123+
assertEquals(1001, ((TestClass) factory.createIntFunction(TestClass.class.getDeclaredConstructor(int.class)).apply(1001)).intField);
124+
assertEquals(1002L, ((TestClass) factory.createLongFunction(TestClass.class.getDeclaredConstructor(long.class)).apply(1002L)).longField);
125+
assertEquals(123.45D, ((TestClass) factory.createDoubleFunction(TestClass.class.getDeclaredConstructor(double.class)).apply(123.45D)).doubleField);
111126
}
112127

113128
@ParameterizedTest

core/src/main/java/com/alibaba/fastjson2/introspect/PropertyAccessorFactory.java

Lines changed: 103 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,40 @@ public Function createFunction(Constructor constructor) {
5454
}
5555

5656
/**
57-
* A Supplier implementation that uses reflection to create new instances
58-
* of a class via its constructor. This class handles constructor accessibility
59-
* and instantiation errors appropriately.
57+
* Creates a Function that can instantiate objects using the given constructor.
58+
* @param constructor the constructor to use for object instantiation
59+
* @return a Function that creates new instances using the provided constructor
6060
*/
61-
static final class ConstructorSupplier implements Supplier {
62-
private final Constructor constructor;
61+
public IntFunction createIntFunction(Constructor constructor) {
62+
return new ConstructorIntFunction(constructor);
63+
}
6364

64-
/**
65-
* Creates a ConstructorSupplier for the given constructor.
66-
* Automatically makes the constructor accessible.
67-
*
68-
* @param constructor the constructor to use for instantiation
69-
*/
70-
public ConstructorSupplier(Constructor constructor) {
65+
/**
66+
* Creates a Function that can instantiate objects using the given constructor.
67+
* @param constructor the constructor to use for object instantiation
68+
* @return a Function that creates new instances using the provided constructor
69+
*/
70+
public LongFunction createLongFunction(Constructor constructor) {
71+
return new ConstructorLongFunction(constructor);
72+
}
73+
74+
/**
75+
* Creates a Function that can instantiate objects using the given constructor.
76+
* @param constructor the constructor to use for object instantiation
77+
* @return a Function that creates new instances using the provided constructor
78+
*/
79+
public DoubleFunction createDoubleFunction(Constructor constructor) {
80+
return new ConstructorDoubleFunction(constructor);
81+
}
82+
83+
/**
84+
* Base class for Constructor-based Function implementations.
85+
* Handles constructor accessibility and instantiation errors.
86+
*/
87+
abstract static class ConstructorFunctionBase {
88+
protected final Constructor constructor;
89+
90+
public ConstructorFunctionBase(Constructor constructor) {
7191
this.constructor = constructor;
7292
setAccessible();
7393
}
@@ -103,6 +123,17 @@ protected JSONException errorOnSetAccessible(Exception e) {
103123
protected JSONException errorOnNewInstance(Exception e) {
104124
return new JSONException(constructor.toString().concat(" newInstance error"), e);
105125
}
126+
}
127+
128+
/**
129+
* A Supplier implementation that uses reflection to create new instances
130+
* of a class via its constructor. This class handles constructor accessibility
131+
* and instantiation errors appropriately.
132+
*/
133+
static final class ConstructorSupplier extends ConstructorFunctionBase implements Supplier {
134+
public ConstructorSupplier(Constructor constructor) {
135+
super(constructor);
136+
}
106137

107138
/**
108139
* Creates a new instance of the class using the constructor.
@@ -120,54 +151,91 @@ public Object get() {
120151
}
121152
}
122153

123-
static final class ConstructorFunction implements Function {
124-
private final Constructor constructor;
125-
154+
static final class ConstructorFunction extends ConstructorFunctionBase implements Function {
126155
/**
127156
* Creates a ConstructorSupplier for the given constructor.
128157
* Automatically makes the constructor accessible.
129158
*
130159
* @param constructor the constructor to use for instantiation
131160
*/
132161
public ConstructorFunction(Constructor constructor) {
133-
this.constructor = constructor;
134-
setAccessible();
162+
super(constructor);
135163
}
136164

137-
/**
138-
* Makes the constructor accessible, handling any security exceptions
139-
* that might occur during the process.
140-
*/
141-
protected void setAccessible() {
165+
@Override
166+
public Object apply(Object arg) {
142167
try {
143-
constructor.setAccessible(true);
168+
return constructor.newInstance(arg);
144169
} catch (Exception e) {
145-
throw new JSONException(e.getMessage(), e);
170+
throw errorOnNewInstance(e);
146171
}
147172
}
173+
}
148174

175+
/**
176+
* A Supplier implementation that uses reflection to create new instances
177+
* of a class via its constructor. This class handles constructor accessibility
178+
* and instantiation errors appropriately.
179+
*/
180+
static final class ConstructorIntFunction extends ConstructorFunctionBase implements IntFunction {
149181
/**
150-
* Creates a specific JSON exception for constructor accessibility errors.
182+
* Creates a ConstructorSupplier for the given constructor.
183+
* Automatically makes the constructor accessible.
151184
*
152-
* @param e the original exception that occurred
153-
* @return a JSONException with detailed error information
185+
* @param constructor the constructor to use for instantiation
154186
*/
155-
protected JSONException errorOnSetAccessible(Exception e) {
156-
return new JSONException(constructor.toString().concat(" setAccessible error"), e);
187+
public ConstructorIntFunction(Constructor constructor) {
188+
super(constructor);
157189
}
158190

191+
@Override
192+
public Object apply(int arg) {
193+
try {
194+
return constructor.newInstance(arg);
195+
} catch (Exception e) {
196+
throw errorOnNewInstance(e);
197+
}
198+
}
199+
}
200+
201+
/**
202+
* A Supplier implementation that uses reflection to create new instances
203+
* of a class via its constructor. This class handles constructor accessibility
204+
* and instantiation errors appropriately.
205+
*/
206+
static final class ConstructorLongFunction extends ConstructorFunctionBase implements LongFunction {
159207
/**
160-
* Creates a specific JSON exception for constructor instantiation errors.
208+
* Creates a ConstructorSupplier for the given constructor.
209+
* Automatically makes the constructor accessible.
161210
*
162-
* @param e the original exception that occurred
163-
* @return a JSONException with detailed error information
211+
* @param constructor the constructor to use for instantiation
164212
*/
165-
protected JSONException errorOnNewInstance(Exception e) {
166-
return new JSONException(constructor.toString().concat(" newInstance error"), e);
213+
public ConstructorLongFunction(Constructor constructor) {
214+
super(constructor);
167215
}
168216

169217
@Override
170-
public Object apply(Object arg) {
218+
public Object apply(long arg) {
219+
try {
220+
return constructor.newInstance(arg);
221+
} catch (Exception e) {
222+
throw errorOnNewInstance(e);
223+
}
224+
}
225+
}
226+
227+
/**
228+
* A Supplier implementation that uses reflection to create new instances
229+
* of a class via its constructor. This class handles constructor accessibility
230+
* and instantiation errors appropriately.
231+
*/
232+
static final class ConstructorDoubleFunction extends ConstructorFunctionBase implements DoubleFunction {
233+
public ConstructorDoubleFunction(Constructor constructor) {
234+
super(constructor);
235+
}
236+
237+
@Override
238+
public Object apply(double arg) {
171239
try {
172240
return constructor.newInstance(arg);
173241
} catch (Exception e) {

core/src/main/java/com/alibaba/fastjson2/introspect/PropertyAccessorFactoryLambda.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,80 @@ public Function createFunction(Constructor constructor) {
8585
}
8686
}
8787

88+
public IntFunction createIntFunction(Constructor constructor) {
89+
try {
90+
Class<?> declaringClass = constructor.getDeclaringClass();
91+
MethodHandles.Lookup lookup = JDKUtils.trustedLookup(declaringClass);
92+
Class<?>[] parameterTypes = constructor.getParameterTypes();
93+
Class<?> param0 = parameterTypes[0];
94+
95+
MethodHandle methodHandle = lookup.findConstructor(
96+
declaringClass,
97+
MethodType.methodType(void.class, param0)
98+
);
99+
100+
CallSite callSite = LambdaMetafactory.metafactory(
101+
lookup,
102+
"apply",
103+
METHOD_TYPE_INT_FUNCTION,
104+
METHOD_TYPE_OBJECT_INT,
105+
methodHandle,
106+
MethodType.methodType(declaringClass, box(param0))
107+
);
108+
return (IntFunction) callSite.getTarget().invokeExact();
109+
} catch (Throwable ignored) {
110+
return super.createIntFunction(constructor);
111+
}
112+
}
113+
114+
public LongFunction createLongFunction(Constructor constructor) {
115+
try {
116+
Class<?> declaringClass = constructor.getDeclaringClass();
117+
MethodHandles.Lookup lookup = JDKUtils.trustedLookup(declaringClass);
118+
Class<?>[] parameterTypes = constructor.getParameterTypes();
119+
Class<?> param0 = parameterTypes[0];
120+
MethodHandle methodHandle = lookup.findConstructor(
121+
declaringClass,
122+
MethodType.methodType(void.class, param0)
123+
);
124+
CallSite callSite = LambdaMetafactory.metafactory(
125+
lookup,
126+
"apply",
127+
METHOD_TYPE_LONG_FUNCTION,
128+
METHOD_TYPE_OBJECT_LONG,
129+
methodHandle,
130+
MethodType.methodType(declaringClass, box(param0))
131+
);
132+
return (LongFunction) callSite.getTarget().invokeExact();
133+
} catch (Throwable ignored) {
134+
return super.createLongFunction(constructor);
135+
}
136+
}
137+
138+
public DoubleFunction createDoubleFunction(Constructor constructor) {
139+
try {
140+
Class<?> declaringClass = constructor.getDeclaringClass();
141+
MethodHandles.Lookup lookup = JDKUtils.trustedLookup(declaringClass);
142+
Class<?>[] parameterTypes = constructor.getParameterTypes();
143+
Class<?> param0 = parameterTypes[0];
144+
MethodHandle methodHandle = lookup.findConstructor(
145+
declaringClass,
146+
MethodType.methodType(void.class, param0)
147+
);
148+
CallSite callSite = LambdaMetafactory.metafactory(
149+
lookup,
150+
"apply",
151+
METHOD_TYPE_DOUBLE_FUNCTION,
152+
METHOD_TYPE_OBJECT_DOUBLE,
153+
methodHandle,
154+
MethodType.methodType(declaringClass, box(param0))
155+
);
156+
return (DoubleFunction) callSite.getTarget().invokeExact();
157+
} catch (Throwable ignored) {
158+
return super.createDoubleFunction(constructor);
159+
}
160+
}
161+
88162
static Class<?> box(Class cls) {
89163
if (cls == int.class) {
90164
return Integer.class;

core/src/main/java/com/alibaba/fastjson2/util/TypeUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public class TypeUtils {
5050
public static final MethodType METHOD_TYPE_OBJECT_INT_CONSUMER = MethodType.methodType(ObjIntConsumer.class);
5151
public static final MethodType METHOD_TYPE_INT_FUNCTION = MethodType.methodType(IntFunction.class);
5252
public static final MethodType METHOD_TYPE_LONG_FUNCTION = MethodType.methodType(LongFunction.class);
53+
public static final MethodType METHOD_TYPE_DOUBLE_FUNCTION = MethodType.methodType(DoubleFunction.class);
5354
public static final MethodType METHOD_TYPE_BI_FUNCTION = MethodType.methodType(BiFunction.class);
5455
public static final MethodType METHOD_TYPE_BI_CONSUMER = MethodType.methodType(BiConsumer.class);
5556
public static final MethodType METHOD_TYPE_VOO = MethodType.methodType(void.class, Object.class, Object.class);
@@ -60,6 +61,7 @@ public class TypeUtils {
6061
public static final MethodType METHOD_TYPE_LONG_OBJECT = MethodType.methodType(long.class, Object.class);
6162
public static final MethodType METHOD_TYPE_VOID_OBJECT_INT = MethodType.methodType(void.class, Object.class, int.class);
6263
public static final MethodType METHOD_TYPE_OBJECT_LONG = MethodType.methodType(Object.class, long.class);
64+
public static final MethodType METHOD_TYPE_OBJECT_DOUBLE = MethodType.methodType(Object.class, double.class);
6365
public static final MethodType METHOD_TYPE_VOID_LONG = MethodType.methodType(void.class, long.class);
6466
public static final MethodType METHOD_TYPE_OBJECT_OBJECT_OBJECT = MethodType.methodType(Object.class, Object.class, Object.class);
6567

0 commit comments

Comments
 (0)