com.caoccao.javet.interop.callback.V8FunctionCallback Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javet-linux-arm64 Show documentation
Show all versions of javet-linux-arm64 Show documentation
Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.
/*
* Copyright (c) 2021-2024. caoccao.com Sam Cao
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.caoccao.javet.interop.callback;
import com.caoccao.javet.exceptions.JavetError;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.interop.converters.IJavetConverter;
import com.caoccao.javet.interop.converters.JavetConverterConfig;
import com.caoccao.javet.utils.*;
import com.caoccao.javet.values.IV8Value;
import com.caoccao.javet.values.V8Value;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
/**
* The type V8 function callback.
*
* @since 0.8.3
*/
public final class V8FunctionCallback {
private static final String NULL = "null";
private static Object convert(IJavetConverter converter, Class> expectedClass, V8Value v8Value)
throws JavetException {
if (v8Value == null) {
// This check is for null safety.
if (expectedClass.isPrimitive()) {
/*
* The following test is based on statistical analysis
* so that the performance can be maximized.
*/
JavetConverterConfig> config = converter.getConfig();
if (expectedClass == int.class) {
return config.getDefaultInt();
} else if (expectedClass == boolean.class) {
return config.getDefaultBoolean();
} else if (expectedClass == double.class) {
return config.getDefaultDouble();
} else if (expectedClass == float.class) {
return config.getDefaultFloat();
} else if (expectedClass == long.class) {
return config.getDefaultLong();
} else if (expectedClass == short.class) {
return config.getDefaultShort();
} else if (expectedClass == byte.class) {
return config.getDefaultByte();
} else if (expectedClass == char.class) {
return config.getDefaultChar();
}
} else if (expectedClass == Optional.class) {
return Optional.empty();
} else if (expectedClass == OptionalInt.class) {
return OptionalInt.empty();
} else if (expectedClass == OptionalDouble.class) {
return OptionalDouble.empty();
} else if (expectedClass == OptionalLong.class) {
return OptionalLong.empty();
} else if (expectedClass == Stream.class) {
return Stream.empty();
} else if (expectedClass == IntStream.class) {
return IntStream.empty();
} else if (expectedClass == DoubleStream.class) {
return DoubleStream.empty();
} else if (expectedClass == LongStream.class) {
return LongStream.empty();
}
} else if (expectedClass.isAssignableFrom(v8Value.getClass())) {
// Skip assignable
} else {
Object convertedObject = converter.toObject(v8Value);
try {
if (convertedObject == null) {
return convert(converter, expectedClass, null);
} else {
Class> convertedObjectClass = convertedObject.getClass();
if (expectedClass.isAssignableFrom(convertedObjectClass)) {
return convertedObject;
} else if (expectedClass.isPrimitive()) {
/*
* The following test is based on statistical analysis
* so that the performance can be maximized.
*/
if (expectedClass == int.class) {
if (convertedObjectClass == Integer.class) {
//noinspection UnnecessaryUnboxing
return ((Integer) convertedObject).intValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).intValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).intValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).intValue();
}
} else if (expectedClass == boolean.class && convertedObjectClass == Boolean.class) {
//noinspection UnnecessaryUnboxing
return ((Boolean) convertedObject).booleanValue();
} else if (expectedClass == double.class) {
if (convertedObjectClass == Double.class) {
//noinspection UnnecessaryUnboxing
return ((Double) convertedObject).doubleValue();
} else if (convertedObjectClass == Float.class) {
return ((Float) convertedObject).doubleValue();
} else if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).doubleValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).doubleValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).doubleValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).doubleValue();
}
} else if (expectedClass == float.class) {
if (convertedObjectClass == Double.class) {
return ((Double) convertedObject).floatValue();
} else if (convertedObjectClass == Float.class) {
//noinspection UnnecessaryUnboxing
return ((Float) convertedObject).floatValue();
} else if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).floatValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).floatValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).floatValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).floatValue();
}
} else if (expectedClass == long.class) {
if (convertedObjectClass == Long.class) {
//noinspection UnnecessaryUnboxing
return ((Long) convertedObject).longValue();
} else if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).longValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).longValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).longValue();
}
} else if (expectedClass == short.class) {
if (convertedObjectClass == Short.class) {
//noinspection UnnecessaryUnboxing
return ((Short) convertedObject).shortValue();
} else if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).shortValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).shortValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).shortValue();
}
} else if (expectedClass == byte.class) {
if (convertedObjectClass == Byte.class) {
//noinspection UnnecessaryUnboxing
return ((Byte) convertedObject).byteValue();
} else if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).byteValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).byteValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).byteValue();
}
} else if (expectedClass == char.class) {
if (convertedObjectClass == Character.class) {
//noinspection UnnecessaryUnboxing
return ((Character) convertedObject).charValue();
} else if (convertedObjectClass == String.class) {
String convertedString = (String) convertedObject;
return StringUtils.isNotEmpty(convertedString) ?
convertedString.charAt(0) : converter.getConfig().getDefaultChar();
}
}
} else if (expectedClass == Integer.class) {
if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).intValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).intValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).intValue();
}
} else if (expectedClass == Double.class) {
if (convertedObjectClass == Float.class) {
return ((Float) convertedObject).doubleValue();
} else if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).doubleValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).doubleValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).doubleValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).doubleValue();
}
} else if (expectedClass == Float.class) {
if (convertedObjectClass == Double.class) {
return ((Double) convertedObject).floatValue();
} else if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).floatValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).floatValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).floatValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).floatValue();
}
} else if (expectedClass == Long.class) {
if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).longValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).longValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).longValue();
}
} else if (expectedClass == Short.class) {
if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).shortValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).shortValue();
} else if (convertedObjectClass == Byte.class) {
return ((Byte) convertedObject).shortValue();
}
} else if (expectedClass == Byte.class) {
if (convertedObjectClass == Integer.class) {
return ((Integer) convertedObject).byteValue();
} else if (convertedObjectClass == Long.class) {
return ((Long) convertedObject).byteValue();
} else if (convertedObjectClass == Short.class) {
return ((Short) convertedObject).byteValue();
}
} else if (expectedClass == Character.class) {
if (convertedObjectClass == String.class) {
String convertedString = (String) convertedObject;
return StringUtils.isNotEmpty(convertedString) ?
convertedString.charAt(0) : converter.getConfig().getDefaultChar();
}
} else if (expectedClass == Optional.class) {
return Optional.of(convertedObject);
} else if (expectedClass == OptionalInt.class) {
if (convertedObject instanceof Integer) {
return OptionalInt.of((Integer) convertedObject);
}
} else if (expectedClass == OptionalDouble.class) {
if (convertedObject instanceof Double) {
return OptionalDouble.of((Double) convertedObject);
}
} else if (expectedClass == OptionalLong.class) {
if (convertedObject instanceof Long) {
return OptionalLong.of((Long) convertedObject);
}
} else if (expectedClass == Stream.class) {
Stream> stream = JavetTypeUtils.toStream(convertedObject);
if (stream != null) {
return stream;
}
} else if (expectedClass == IntStream.class) {
IntStream intStream = JavetTypeUtils.toIntStream(convertedObject);
if (intStream != null) {
return intStream;
}
} else if (expectedClass == LongStream.class) {
LongStream longStream = JavetTypeUtils.toLongStream(convertedObject);
if (longStream != null) {
return longStream;
}
} else if (expectedClass == DoubleStream.class) {
DoubleStream doubleStream = JavetTypeUtils.toDoubleStream(convertedObject);
if (doubleStream != null) {
return doubleStream;
}
}
}
} catch (Throwable ignored) {
}
throw new JavetException(
JavetError.CallbackSignatureParameterTypeMismatch,
SimpleMap.of(
JavetError.PARAMETER_EXPECTED_PARAMETER_TYPE, expectedClass,
JavetError.PARAMETER_ACTUAL_PARAMETER_TYPE, convertedObject == null ? NULL : convertedObject.getClass()));
}
return v8Value;
}
/**
* Receive callback and return the V8 value.
*
* @param v8Runtime the V8 runtime
* @param javetCallbackContext the javet callback context
* @param thisObject this object
* @param args the args
* @return the V8 value
* @throws Throwable the throwable
* @since 0.8.3
*/
public static V8Value receiveCallback(
V8Runtime v8Runtime,
JavetCallbackContext javetCallbackContext,
V8Value thisObject,
V8Value[] args) throws Throwable {
if (javetCallbackContext != null) {
Object resultObject = null;
try {
/*
* Converter is the key to automatic type conversion.
* If the call doesn't want automatic type conversion,
* it's better to inject V8Runtime via @V8RuntimeSetter
* to the receiver so that the receiver can create reference V8Value.
*/
IJavetConverter converter = v8Runtime.getConverter();
if (javetCallbackContext.getCallbackType() == JavetCallbackType.Reflection) {
/*
* Javet doesn't check whether callback method is static or not.
* If the callback receiver is null, that's a static method.
*/
Method method = javetCallbackContext.getCallbackMethod();
JavetReflectionUtils.safeSetAccessible(method);
Object callbackReceiver = javetCallbackContext.getCallbackReceiver();
List