OpcUaVariant
OpcUaVariant 是 OPC UA 的通用值容器, 覆盖 OPC UA 全部内置数据类型. SDK 用它在 Java 与 native 之间传值.
实现 AutoCloseable — 持有 native handle, 必须 close.
配套
- 包装值 + 时间戳 + 状态请看 OpcUaDataValue.
- 标准节点常量请看 WellKnownNodes.
公共方法
| 类别 | 属性 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| 状态 | handle() | Pointer | R | 内部 native handle (调试用) |
getDataType() | Enums.BuiltinType | R | 内置数据类型 | |
| 构造 / 设值 | setBoolean / setSByte / setByte / setInt16 / setUInt16 / setInt32 / setUInt32 / setInt64 / setFloat / setDouble / setString / setDateTime | OpcUaVariant (this) | W | 链式设值, 返回自身 |
| 取值 | asBoolean() | Boolean | R | 类型不匹配返回 null |
asInt32() | Integer | R | 类型不匹配返回 null | |
asUInt32() | Long | R | 用 Long 容纳无符号 | |
asInt64() | Long | R | 类型不匹配返回 null | |
asDouble() | Double | R | 类型不匹配返回 null | |
asString() | String | R | 类型不匹配返回 null | |
asFileTime() | long | R | DateTime 取 Windows FileTime, 0 = 空 | |
| tryGet 风格 | tryGetBoolean(IntByReference) | boolean | R | 成功返回 true, 输出存到 IntByReference |
tryGetInt32 / tryGetUInt32 / tryGetInt64 / tryGetDouble | boolean | R | 同上, 输出对应类型 ByReference | |
| 释放 | close() | void | — | 释放 native 内存 (owns=true 时) |
构造与设值 (链式)
new OpcUaVariant().setBoolean(true) // Boolean
new OpcUaVariant().setSByte((byte) -1) // SByte
new OpcUaVariant().setByte(255) // Byte
new OpcUaVariant().setInt16((short) 42) // Int16
new OpcUaVariant().setUInt16(42) // UInt16
new OpcUaVariant().setInt32(42) // Int32
new OpcUaVariant().setUInt32(42) // UInt32
new OpcUaVariant().setInt64(42L) // Int64
new OpcUaVariant().setFloat(3.14f) // Float
new OpcUaVariant().setDouble(3.14) // Double
new OpcUaVariant().setString("hello") // String
new OpcUaVariant().setDateTime(fileTimeLong) // DateTime (Windows FileTime)
读取 (强类型)
try (OpcUaDataValue dv = ua.read("ns=2;s=T1")) {
OpcUaVariant v = dv.variant(); // 不持有, 不要 close
Double d = v.asDouble(); // null = 类型不匹配
Integer i = v.asInt32();
String s = v.asString();
Boolean b = v.asBoolean();
long ft = v.asFileTime(); // DateTime
}
类型不匹配返回 null (Java SDK 风格), 不抛异常 — 上层显式 null 判断.
tryGet (out 风格)
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.DoubleByReference;
OpcUaVariant v = dv.variant();
IntByReference outI = new IntByReference();
if (v.tryGetInt32(outI)) {
int n = outI.getValue();
}
DoubleByReference outD = new DoubleByReference();
if (v.tryGetDouble(outD)) {
double x = outD.getValue();
}
DateTime ↔ Instant
import java.time.Instant;
// FileTime → Instant
long ft = v.asFileTime();
Instant t = (ft > 0)
? Instant.ofEpochMilli((ft - 116444736000000000L) / 10000L)
: Instant.now();
// Instant → FileTime
long ft2 = t.toEpochMilli() * 10000L + 116444736000000000L;
v.setDateTime(ft2);
toString
OpcUaVariant.toString() 按 DataType 智能格式化:
| DataType | 输出示例 |
|---|---|
| Double / Float | 3.14 |
| Int32 / UInt32 | 42 |
| String | hello |
| DateTime | ft=132456... (FileTime raw, 自己转 Instant 显示) |
| 其他 | <TypeName> |
内存所有权
OpcUaVariant 包装 native handle, 实现 AutoCloseable:
| 来源 | owns | 是否要 close |
|---|---|---|
new OpcUaVariant() 构造 | true | 是 |
ua.read(...) 间接持有 (经 OpcUaDataValue) | — | 由 OpcUaDataValue 接管 |
ua.call(...) 返回的 outputs | true | 是 (逐项 close) |
OpcUaDataValue.variant() 返回 | false | 否 (随 DataValue 一起释放) |
最佳实践:
try (OpcUaVariant v = new OpcUaVariant().setDouble(42.0)) {
ua.write("ns=2;s=X", v);
} // 自动 close
漏 close 后果
漏 close 会泄漏 native 内存 (定时跑 100k+ 次会涨内存). 永远用 try-with-resources 包构造的 OpcUaVariant.
BuiltinType 完整清单 (Enums.BuiltinType)
Null (0), Boolean (1), SByte (2), Byte (3),
Int16 (4), UInt16 (5), Int32 (6), UInt32 (7), Int64 (8), UInt64 (9),
Float (10), Double (11), String (12), DateTime (13), Guid (14),
ByteString (15), XmlElement (16), NodeId (17), ExpandedNodeId (18),
StatusCode (19), QualifiedName (20), LocalizedText (21),
ExtensionObject (22), DataValue (23), Variant (24), DiagnosticInfo (25)
数组类型
当前 Java SDK Variant 暴露的 setXxx/asXxx 主要面向标量. 数组场景请通过底层 native 接口或后续版本扩展.
ExtensionObject (复杂结构)
OPC UA Server 自定义 Struct DataType 通过 ExtensionObject 包装. 当前 SDK 提供基础 ExtensionObject 容器, 完整 schema 解析在后续版本.