• graalvm js 与java 类型转换的一些方法


    在基于跨不同语言的通信开发中,数据类型的转换是一个很大的部分,目前来说graalvm 对于java host 类型与js 对象类似的转换还是不够好
    java host 对象到js 的操作我们可以通过ProxyObject 以及提供的HostAccess 注解处理

    参考模式

    • js 到java 对象转换
      这个对应的数据类型还是比较多的,比如普通类型以及java 的pojo 类型
      简单类型,graalvm 已经提供了as 方法,但是不是很好的地方是当前不支持直接到pojo,我们需要转换为其他支持的类型再处理,一般我们
      日常会使用到的类型有array,string,int,object 。。。。,为了方便我们可以结合 jackson-databind 来处理类型转换
      pojo 的我们解决map 类型到pojo 的转换处理
      参考代码
     
    Value execResult =result.execute(ProxyObject.fromMap(ob),filed);
    Map<String, Object> results = execResult.as(Map.class);
    System.out.println("demoappa"+execResult.as(List.class));
    ObjectMapper objectMapper = new ObjectMapper();
    CollectionType javaType = objectMapper.getTypeFactory()
        .constructCollectionType(List.class, MyUser.class);
    List myusers = execResult.as(List.class);
    System.out.println("myusers"+myusers);
    ArrayList<MyUser> users = objectMapper.convertValue(myusers, javaType);
    System.out.println("dalong"+users);

    Array 类型的转换:
    通过Value 提供的as List 转换

     
    Value execResult =result.execute(ProxyObject.fromMap(ob),filed);
    Map<String, Object> results = execResult.as(Map.class);
    ObjectMapper objectMapper = new ObjectMapper();
    CollectionType javaType = objectMapper.getTypeFactory()
        .constructCollectionType(List.class, MyUser.class);
    List<? extends Object> myusers = execResult.as(List.class);
    System.out.println("myusers---"+(List<MyUser>)myusers);
    ArrayList<MyUser> users = objectMapper.convertValue(myusers, javaType);
    System.out.println("dalong"+users);

    目前内部转换的支持代码(后期可能会变)

     @TruffleBoundary
        private static <T> T asJavaObject(Object value, Class<T> targetType, Type genericType, boolean allowsImplementation, PolyglotLanguageContext languageContext) {
            Objects.requireNonNull(value);
            InteropLibrary interop = InteropLibrary.getFactory().getUncached(value);
            Object obj;
            if (interop.isNull(value)) {
                if (targetType.isPrimitive()) {
                    throw HostInteropErrors.nullCoercion(languageContext, value, targetType);
                }
                return null;
            } else if (HostObject.isJavaInstance(targetType, value)) {
                obj = HostObject.valueOf(value);
            } else if (targetType == Object.class) {
                obj = convertToObject(value, languageContext, interop);
            } else if (targetType == List.class) {
                if (interop.hasArrayElements(value)) {
                    boolean implementsFunction = shouldImplementFunction(value, interop);
                    TypeAndClass<?> elementType = getGenericParameterType(genericType, 0);
                    obj = PolyglotList.create(languageContext, value, implementsFunction, elementType.clazz, elementType.type);
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have array elements.");
                }
            } else if (targetType == Map.class) {
                Class<?> keyClazz = getGenericParameterType(genericType, 0).clazz;
                TypeAndClass<?> valueType = getGenericParameterType(genericType, 1);
                if (!isSupportedMapKeyType(keyClazz)) {
                    throw newInvalidKeyTypeException(keyClazz);
                }
                boolean hasSize = (Number.class.isAssignableFrom(keyClazz)) && interop.hasArrayElements(value);
                boolean hasKeys = (keyClazz == Object.class || keyClazz == String.class) && interop.hasMembers(value);
                if (hasKeys || hasSize) {
                    boolean implementsFunction = shouldImplementFunction(value, interop);
                    obj = PolyglotMap.create(languageContext, value, implementsFunction, keyClazz, valueType.clazz, valueType.type);
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have members or array elements.");
                }
            } else if (targetType == Function.class) {
                TypeAndClass<?> returnType = getGenericParameterType(genericType, 1);
                if (interop.isExecutable(value) || interop.isInstantiable(value)) {
                    obj = PolyglotFunction.create(languageContext, value, returnType.clazz, returnType.type);
                } else if (interop.hasMembers(value)) {
                    obj = HostInteropReflect.newProxyInstance(targetType, value, languageContext);
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must be executable or instantiable.");
                }
            } else if (targetType.isArray()) {
                if (interop.hasArrayElements(value)) {
                    obj = truffleObjectToArray(interop, value, targetType, genericType, languageContext);
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have array elements.");
                }
            } else if (targetType == LocalDate.class) {
                if (interop.isDate(value)) {
                    try {
                        obj = interop.asDate(value);
                    } catch (UnsupportedMessageException e) {
                        throw shouldNotReachHere(e);
                    }
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have date and time information.");
                }
            } else if (targetType == LocalTime.class) {
                if (interop.isTime(value)) {
                    try {
                        obj = interop.asTime(value);
                    } catch (UnsupportedMessageException e) {
                        throw shouldNotReachHere(e);
                    }
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have date and time information.");
                }
            } else if (targetType == LocalDateTime.class) {
                if (interop.isDate(value) && interop.isTime(value)) {
                    LocalDate date;
                    LocalTime time;
                    try {
                        date = interop.asDate(value);
                        time = interop.asTime(value);
                    } catch (UnsupportedMessageException e) {
                        throw shouldNotReachHere(e);
                    }
                    obj = createDateTime(date, time);
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have date and time information.");
                }
            } else if (targetType == ZonedDateTime.class) {
                if (interop.isDate(value) && interop.isTime(value) && interop.isTimeZone(value)) {
                    LocalDate date;
                    LocalTime time;
                    ZoneId timeZone;
                    try {
                        date = interop.asDate(value);
                        time = interop.asTime(value);
                        timeZone = interop.asTimeZone(value);
                    } catch (UnsupportedMessageException e) {
                        throw shouldNotReachHere(e);
                    }
                    obj = createZonedDateTime(date, time, timeZone);
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have date, time and time-zone information.");
                }
            } else if (targetType == ZoneId.class) {
                if (interop.isTimeZone(value)) {
                    try {
                        obj = interop.asTimeZone(value);
                    } catch (UnsupportedMessageException e) {
                        throw shouldNotReachHere(e);
                    }
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have time-zone information.");
                }
            } else if (targetType == Instant.class || targetType == Date.class) {
                if (interop.isDate(value) && interop.isTime(value) && interop.isTimeZone(value)) {
                    Instant instantValue;
                    try {
                        instantValue = interop.asInstant(value);
                    } catch (UnsupportedMessageException e) {
                        throw shouldNotReachHere(e);
                    }
                    if (targetType == Date.class) {
                        obj = Date.from(instantValue);
                    } else {
                        obj = targetType.cast(instantValue);
                    }
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have date, time and time-zone information.");
                }
            } else if (targetType == Duration.class) {
                if (interop.isDuration(value)) {
                    try {
                        obj = interop.asDuration(value);
                    } catch (UnsupportedMessageException e) {
                        throw shouldNotReachHere(e);
                    }
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have duration information.");
                }
            } else if (targetType == PolyglotException.class) {
                if (interop.isException(value)) {
                    obj = asPolyglotException(value, interop, languageContext);
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must be an exception.");
                }
            } else if (allowsImplementation && targetType.isInterface()) {
                if (HostInteropReflect.isFunctionalInterface(targetType) && (interop.isExecutable(value) || interop.isInstantiable(value))) {
                    obj = HostInteropReflect.asJavaFunction(targetType, value, languageContext);
                } else if (interop.hasMembers(value)) {
                    obj = HostInteropReflect.newProxyInstance(targetType, value, languageContext);
                } else {
                    throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Value must have members.");
                }
            } else {
                throw HostInteropErrors.cannotConvert(languageContext, value, targetType, "Unsupported target type.");
            }
            assert targetType.isInstance(obj);
            return targetType.cast(obj);
        }
    • java host object && meethod 2 js
      对于object 类型,比较推荐的是通过ProxyObject 进行map转换处理(对应到js 的object)
      java 代码:
     
    Map<String, Object> ob =new HashMap<>();
    Map<String, Object> ob2 =new HashMap<>();
    ob2.put("url","https://plus.google.com/102817283354809142195/posts/F97fqZwJESL");
    ob.put("url","https://plus.google.com/102817283354809142195/posts/F97fqZwJESL");
    Map<String, Object> ob3 =new HashMap<>();
    ob3.put("url","https://plus.google.com/102817283354809142195/posts/F97fqZwJESL");
    ob2.put("ob",ProxyObject.fromMap(ob3));
    ob.put("id","z12gtjhq3qn2xxl2o224exwiqruvtda0i");
    ob.put("object",ProxyObject.fromMap(ob2));

    js 代码:

    window = this || {}
    window.demo = function (datas, fields) {
        let mydatas 
        mydatas = datas;
        if (typeof datas === 'string') {
            mydatas =JSON.parse(datas)
        }
        return mask(mydatas, fields)
    }

    普通java对象通过 @HostAccess 注解暴露

    public class Dalong {
        @HostAccess.Export
        public   String  username;
        @HostAccess.Export
        public   String  password;
        @HostAccess.Export
        public  String token() {
            return String.format("%s------%s",this.username,this.password);
        }
    }

    使用

    Dalong dalong = new Dalong();
    dalong.password="dalong";
    dalong.username="dalong";
    Context context = Context.newBuilder().allowAllAccess(true).allowHostClassLoading(true).allowHostAccess(hostAccess).allowIO(true).allowNativeAccess(true).engine(engine).build();
    context.getBindings("js").putMember("mydalong",dalong);
    System.out.println(context.getBindings("js").getMemberKeys());
    String myjs = "mydalong.username= "dalongdemossss";
    " +
            "mydalong.password= "deeeeeeee";
    " +
            "
    " +
            "console.log("my token",mydalong.token())
    " +
            "
    ";
    context.eval("js",myjs);

    说明

    以上是一些自己简单的整理,实际应该还会有其他更方便的方法,graalvm 的js 能力很强大,很值得使用

    参考资料

    https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html
    https://github.com/AMIS-Services/jfall2019-graalvm/tree/master/polyglot/java2js
    https://github.com/graalvm/graaljs/issues/94

  • 相关阅读:
    【产品干货】经典营销模型的产品化介绍
    阿里云力夺FewCLUE榜首!知识融入预训练+小样本学习的实战解析
    云上资源编排的思与悟
    储留香:一个智能运维系统就是一个中枢神经系统,我说的!
    企业网管软件之SOLARWINDS实战-制作拓扑图
    企业网管软件之SOLARWINDS实战-基于浏览器的网络流量监控
    企业网管软件实战之看视频学装Cisco Works 2000
    轻松学习Linux之Shell预定义变量
    oracle的监听日志太大,正确的删除步骤
    MVC 使用HandleErrorAttribute统一处理异常
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/13589050.html
Copyright © 2020-2023  润新知