Skip to content

Commit 38b7345

Browse files
committed
createBiFunction
1 parent 5d696c1 commit 38b7345

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,24 @@ public DoubleFunction createDoubleFunction(Constructor constructor) {
140140
}
141141
}
142142

143+
@Override
144+
public BiFunction createBiFunction(Constructor constructor) {
145+
try {
146+
MethodHandles.Lookup lookup = lookup(constructor.getDeclaringClass());
147+
MethodHandle methodHandle = lookup.unreflectConstructor(constructor);
148+
return (arg1, arg2) -> {
149+
try {
150+
return methodHandle.invoke(arg1, arg2);
151+
} catch (Throwable e) {
152+
throw new RuntimeException(e);
153+
}
154+
};
155+
} catch (Throwable ignored) {
156+
// ignore
157+
return super.createBiFunction(constructor);
158+
}
159+
}
160+
143161
/**
144162
* Creates a property accessor for the given field using MethodHandle-based implementation.
145163
* 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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.lang.reflect.Method;
1010
import java.math.BigDecimal;
1111
import java.math.BigInteger;
12+
import java.util.function.BiFunction;
1213

1314
import static org.junit.jupiter.api.Assertions.*;
1415

@@ -58,6 +59,11 @@ public TestClass(double doubleField) {
5859
public TestClass(Byte byteObjField) {
5960
this.byteObjField = byteObjField;
6061
}
62+
63+
public TestClass(Character charObjField, Short shortObjField) {
64+
this.charObjField = charObjField;
65+
this.shortObjField = shortObjField;
66+
}
6167
}
6268

6369
public static java.util.Map<Class<?>, Field> fieldMap = new java.util.HashMap<>();
@@ -123,6 +129,12 @@ public void allocate(PropertyAccessorFactory factory) throws Exception {
123129
assertEquals(1001, ((TestClass) factory.createIntFunction(TestClass.class.getDeclaredConstructor(int.class)).apply(1001)).intField);
124130
assertEquals(1002L, ((TestClass) factory.createLongFunction(TestClass.class.getDeclaredConstructor(long.class)).apply(1002L)).longField);
125131
assertEquals(123.45D, ((TestClass) factory.createDoubleFunction(TestClass.class.getDeclaredConstructor(double.class)).apply(123.45D)).doubleField);
132+
{
133+
BiFunction biFunction = factory.createBiFunction(TestClass.class.getDeclaredConstructor(Character.class, Short.class));
134+
TestClass x = (TestClass) biFunction.apply('X', (short) 100);
135+
assertEquals('X', x.charObjField);
136+
assertEquals((short) 100, x.shortObjField);
137+
}
126138
}
127139

128140
@ParameterizedTest

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ public DoubleFunction createDoubleFunction(Constructor constructor) {
8080
return new ConstructorDoubleFunction(constructor);
8181
}
8282

83+
/**
84+
* Creates a BiFunction that can instantiate objects using the given constructor.
85+
* @param constructor the constructor to use for object instantiation
86+
* @return a BiFunction that creates new instances using the provided constructor
87+
*/
88+
public BiFunction createBiFunction(Constructor constructor) {
89+
return new ConstructorBiFunction(constructor);
90+
}
91+
8392
/**
8493
* Base class for Constructor-based Function implementations.
8594
* Handles constructor accessibility and instantiation errors.
@@ -244,6 +253,32 @@ public Object apply(double arg) {
244253
}
245254
}
246255

256+
/**
257+
* A Supplier implementation that uses reflection to create new instances
258+
* of a class via its constructor. This class handles constructor accessibility
259+
* and instantiation errors appropriately.
260+
*/
261+
static final class ConstructorBiFunction extends ConstructorFunctionBase implements BiFunction {
262+
/**
263+
* Creates a ConstructorBiFunction for the given constructor.
264+
* Automatically makes the constructor accessible.
265+
*
266+
* @param constructor the constructor to use for instantiation
267+
*/
268+
public ConstructorBiFunction(Constructor constructor) {
269+
super(constructor);
270+
}
271+
272+
@Override
273+
public Object apply(Object t, Object u) {
274+
try {
275+
return constructor.newInstance(t, u);
276+
} catch (Exception e) {
277+
throw errorOnNewInstance(e);
278+
}
279+
}
280+
}
281+
247282
/**
248283
* Creates a property accessor for the specified field.
249284
* This method analyzes the field type and returns an appropriate

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,32 @@ public DoubleFunction createDoubleFunction(Constructor constructor) {
159159
}
160160
}
161161

162+
@Override
163+
public BiFunction createBiFunction(Constructor constructor) {
164+
try {
165+
Class<?> declaringClass = constructor.getDeclaringClass();
166+
MethodHandles.Lookup lookup = JDKUtils.trustedLookup(declaringClass);
167+
Class<?>[] parameterTypes = constructor.getParameterTypes();
168+
Class<?> param0 = parameterTypes[0];
169+
Class<?> param1 = parameterTypes[1];
170+
MethodHandle methodHandle = lookup.findConstructor(
171+
declaringClass,
172+
MethodType.methodType(void.class, param0, param1)
173+
);
174+
CallSite callSite = LambdaMetafactory.metafactory(
175+
lookup,
176+
"apply",
177+
METHOD_TYPE_BI_FUNCTION,
178+
METHOD_TYPE_OBJECT_OBJECT_OBJECT,
179+
methodHandle,
180+
MethodType.methodType(declaringClass, box(param0), box(param1))
181+
);
182+
return (BiFunction) callSite.getTarget().invokeExact();
183+
} catch (Throwable ignored) {
184+
return super.createBiFunction(constructor);
185+
}
186+
}
187+
162188
static Class<?> box(Class cls) {
163189
if (cls == int.class) {
164190
return Integer.class;

0 commit comments

Comments
 (0)