Aria 运行在 JVM 上,提供了完整的 Java 互操作能力。通过 use() 函数可以加载 Java 类、创建实例、调用方法,通过 Java 命名空间可以进行类型转换和接口实现。
val .HashMap = use ( 'java.util.HashMap' )
val .Math = use ( 'java.lang.Math' )
val .ArrayList = use ( 'java.util.ArrayList' )
加载后返回一个类镜像对象(JavaClassMirror),可以访问静态字段、静态方法,以及创建实例。
支持基本类型名称:int、long、double、float、boolean、byte、short、char、void。
支持数组类型:use('int[]')、use('java.lang.String[]')。
Java.type() 仍然可用,作为 use() 的别名保留,以确保向后兼容。
直接调用类名创建 Java 对象实例:
val .StringBuilder = use ( 'java.lang.StringBuilder' )
val .sb = StringBuilder ( 'hello' )
sb. append ( ' world' )
println (sb. toString ()) // "hello world"
val .HashMap = use ( 'java.util.HashMap' )
val .map = HashMap ()
map. put ( 'key' , 'value' )
println (map. get ( 'key' )) // "value"
构造器支持重载解析,会根据参数数量和类型自动选择最佳匹配。
val .Math = use ( 'java.lang.Math' )
// 静态字段
println (Math.PI) // 3.141592653589793
// 静态方法
println (Math. abs ( - 42 )) // 42
println (Math. max ( 3 , 7 )) // 7
val .ArrayList = use ( 'java.util.ArrayList' )
val .list = ArrayList ()
list. add ( 'a' )
list. add ( 'b' )
list. add ( 'c' )
println (list. size ()) // 3
println (list. get ( 1 )) // "b"
方法重载会自动解析。参数类型匹配评分规则:
精确类型匹配优先(如 double 参数传 NumberValue 得分最高)
参数数量精确匹配优先
支持可变参数方法
对于符合 JavaBean 规范的对象,可以直接通过属性名访问 getter:
val .Date = use ( 'java.util.Date' )
val .d = Date ( 0 )
println (d.time) // 0 — 等价于 d.getTime()
支持 getXxx() 和 isXxx()(布尔属性)两种 getter 模式。
公共实例字段和静态字段可以直接通过名称访问:
val .Math = use ( 'java.lang.Math' )
println (Math.PI) // 静态字段
Java 的 List 和 Map 对象支持下标访问:
val .ArrayList = use ( 'java.util.ArrayList' )
val .list = ArrayList ()
list. add ( 'x' )
list. add ( 'y' )
// list[0] 等价于 list.get(0)
val .HashMap = use ( 'java.util.HashMap' )
val .map = HashMap ()
map. put ( 'key' , 'value' )
// map['key'] 等价于 map.get('key')
将 Java 集合/数组转换为 Aria 原生值:
val .ArrayList = use ( 'java.util.ArrayList' )
val .javaList = ArrayList ()
javaList. add ( 1 )
javaList. add ( 2 )
javaList. add ( 3 )
val .ariaList = Java. from (javaList) // 转为 Aria ListValue
println (type. isList (ariaList)) // true
转换规则:
java.util.List → ListValue
java.util.Map → MapValue
Java 数组 → ListValue
其他类型原样返回
将 Aria 值转换为 Java 集合对象:
val .list = [ 10 , 20 , 30 ]
val .javaList = Java. to (list) // 转为 Java ArrayList(包装为 JavaObjectMirror)
val .map = { "a" : 1 , "b" : 2 }
val .javaMap = Java. to (map) // 转为 Java LinkedHashMap
支持两种方式实现 Java 接口。
如果接口只有一个抽象方法,可以直接传入函数:
val .Runnable = use ( 'java.lang.Runnable' )
val .r = Java. extend (Runnable, -> {
println ( "running!" )
})
r. run () // "running!"
val .Comparator = use ( 'java.util.Comparator' )
val .cmp = Java. extend (Comparator, -> {
return args [ 0 ] - args [ 1 ]
})
使用 Map 为每个方法提供实现:
val .MyInterface = use ( 'com.example.MyInterface' )
val .impl = Java. extend (MyInterface, {
"methodA" : -> {
return "hello"
},
"methodB" : -> {
return args [ 0 ] + args [ 1 ]
}
})
未提供实现的方法会返回对应类型的默认值。
注意:Java.extend 仅支持接口,不支持扩展具体类。
返回对象自身。super 调用的实际语义由类系统处理,此方法主要用于兼容性。
val .obj = MyClass ()
Java. super (obj) // 返回 obj 自身
通过 ClassFilter 可以控制脚本能访问哪些 Java 类:
import priv.seventeen.artist.aria.interop.ClassFilter;
import priv.seventeen.artist.aria.interop.JavaInterop;
// 禁止访问 java.io 包
JavaInterop. setClassFilter (className -> ! className. startsWith ( "java.io" ));
// 只允许特定包
JavaInterop. setClassFilter (className ->
className. startsWith ( "java.util." ) ||
className. startsWith ( "java.lang." )
);
// 恢复默认(允许所有)
JavaInterop. setClassFilter (ClassFilter.ALLOW_ALL);
当脚本尝试加载被禁止的类时,会抛出 "Access denied to class: xxx" 异常。
CallableManager 是 Aria 的函数注册中心,提供三级注册机制。
import priv.seventeen.artist.aria.callable.CallableManager;
import priv.seventeen.artist.aria.value. * ;
CallableManager manager = CallableManager.INSTANCE;
// 注册到 "mylib" 命名空间
manager. registerStaticFunction ( "mylib" , "greet" , data -> {
String name = data. get ( 0 ). stringValue ();
return new StringValue ( "Hello, " + name + "!" );
});
// 注册到全局(无命名空间)
manager. registerStaticFunction ( "" , "myGlobalFn" , data -> {
return new NumberValue ( 42 );
});
脚本中调用:
println (mylib. greet ( "Alice" )) // "Hello, Alice!"
println ( myGlobalFn ()) // 42
manager. registerConstructor ( "MyObj" , data -> {
double x = data. get ( 0 ). numberValue ();
double y = data. get ( 1 ). numberValue ();
return new MyAriaObject (x, y); // 需实现 IAriaObject
});
脚本中调用:
// 为 StringValue 注册自定义方法
manager. registerObjectFunction (StringValue.class, "repeat" , data -> {
String s = data. get ( 0 ). stringValue ();
int count = ( int ) data. get ( 1 ). numberValue ();
return new StringValue (s. repeat (count));
});
脚本中调用:
val .s = "ha" . repeat ( 3 ) // "hahaha"
对象方法查找支持继承链:先查当前类,再查父类和接口。
通过注解自动注册构造器和实例方法:
manager. registerObject (MyCustomObject.class);
标注在构造器上,注册为 Aria 对象构造器:
import priv.seventeen.artist.aria.annotation.java.AriaObjectConstructor;
import priv.seventeen.artist.aria.object.IAriaObject;
import priv.seventeen.artist.aria.callable.InvocationData;
public class Point implements IAriaObject {
private double x, y;
@ AriaObjectConstructor ( "Point" )
public Point (InvocationData data ) {
this .x = data. get ( 0 ). numberValue ();
this .y = data. get ( 1 ). numberValue ();
}
@ Override
public String getTypeName () { return "Point" ; }
@ Override
public String stringValue () { return "(" + x + ", " + y + ")" ; }
}
标注在实例方法上,注册为对象方法:
import priv.seventeen.artist.aria.annotation.java.AriaInvokeHandler;
import priv.seventeen.artist.aria.callable.InvocationData;
import priv.seventeen.artist.aria.value.IValue;
import priv.seventeen.artist.aria.value.NumberValue;
public class Point implements IAriaObject {
// ... 构造器省略
@ AriaInvokeHandler ( "distance" )
public IValue< ? > distance (InvocationData data ) {
Point other = (Point) ((ObjectValue <?> ) data. get ( 1 )). jvmValue ();
double dx = this .x - other.x;
double dy = this .y - other.y;
return new NumberValue (Math. sqrt (dx * dx + dy * dy));
}
@ AriaInvokeHandler ( "getX" )
public IValue< ? > getX (InvocationData data ) {
return new NumberValue ( this .x);
}
}
@AriaInvokeHandler 还支持 target 属性指定目标类(默认为 Void.class,表示当前类)。
注册后在脚本中使用:
val .p1 = Point ( 0 , 0 )
val .p2 = Point ( 3 , 4 )
println (p1. distance (p2)) // 5.0
println (p2. getX ()) // 3.0
除了手动调用 registerStaticFunction(namespace, name, callable),还可以用注解声明整个命名空间:
import priv.seventeen.artist.aria.annotation.java.AriaNamespace;
import priv.seventeen.artist.aria.annotation.java.AriaInvokeHandler;
import priv.seventeen.artist.aria.callable.InvocationData;
import priv.seventeen.artist.aria.value. * ;
@ AriaNamespace ({ "Math" , "math" }) // 支持多个别名
public class MathFunctions {
@ AriaInvokeHandler ( "add" )
public static IValue< ? > add (InvocationData data ) {
return new NumberValue (data. get ( 0 ). numberValue () + data. get ( 1 ). numberValue ());
}
@ AriaInvokeHandler ( "multiply" )
public static IValue< ? > multiply (InvocationData data ) {
return new NumberValue (data. get ( 0 ). numberValue () * data. get ( 1 ). numberValue ());
}
}
注册:
CallableManager.INSTANCE. registerStaticFunction (MathFunctions.class);
脚本中两种命名空间都能用:
println (Math. add ( 1 , 2 )) // 3
println (math. multiply ( 3 , 4 )) // 12
规则:
@AriaNamespace 标注在类上,value 是命名空间名数组,第一个为主名,其余为别名
@AriaInvokeHandler 标注在 public static 方法上,参数必须是 InvocationData
返回值自动包装:IValue 直接返回,Double/Number → NumberValue,String → StringValue,Boolean → BooleanValue,null → NoneValue
内部使用 MethodHandle 调用,性能接近直接方法调用
也可以在注册后手动添加别名:
CallableManager.INSTANCE. aliasNamespace ( "Math" , "math" );
// 现在 Math.sin() 和 math.sin() 指向同一个函数表
import priv.seventeen.artist.aria.Aria;
import priv.seventeen.artist.aria.callable.CallableManager;
import priv.seventeen.artist.aria.context.Context;
import priv.seventeen.artist.aria.interop.ClassFilter;
import priv.seventeen.artist.aria.interop.JavaInterop;
import priv.seventeen.artist.aria.value. * ;
public class JavaInteropExample {
public static void main ( String [] args ) throws Exception {
// 1. 设置类过滤器(安全控制)
JavaInterop. setClassFilter (className ->
className. startsWith ( "java.util." ) ||
className. startsWith ( "java.lang." )
);
// 2. 注册自定义函数
CallableManager manager = CallableManager.INSTANCE;
manager. registerStaticFunction ( "app" , "version" , data ->
new StringValue ( "1.0.0" )
);
manager. registerStaticFunction ( "app" , "add" , data -> {
double a = data. get ( 0 ). numberValue ();
double b = data. get ( 1 ). numberValue ();
return new NumberValue (a + b);
});
// 3. 执行脚本
Context ctx = Aria. createContext ();
IValue< ? > result = Aria. eval ( """
val.HashMap = use('java.util.HashMap')
val.map = HashMap()
map.put('version', app.version())
map.put('sum', app.add(10, 20))
return Java.from(map)
""" , ctx);
System.out. println (result);
}
}