mirai
mirai copied to clipboard
在 PluginData 支持可空类型
问题描述
问题:JavaAutoSavePluginData自动保存是没有按照我定义的类型存入变量
public class SessionData extends JavaAutoSavePluginData{
/**
* 唯一构造
*/
public static final SessionData INSTANCE = new SessionData();
/**
* 文件名
*/
public SessionData() {
super("SessionData");
}
public final Value<Map<String,Map<String, String>>> sessionlist = typedValue("sessionlist",
createKType(Map.class,
createKType(String.class),
createKType(Map.class,
createKType(String.class), createKType(String.class)
)
));
}
结果:在不存在数据的时候,可以运行一次,当有数据存入的时候,结果就是报错,提示无法识别,然后插件启动失败
请问一下这样的情况怎么解决,或者能不再指明一条在mirai-console的插件其他数据持久化的方法!
复现
当时发生过一次,现在再照个以上代码测试不确定能再次触发
mirai-core 版本
2.1.0-71ec418
bot-protocol
ANDROID_PHONE
其他组件版本
"net.mamoe:mirai-console" v2.11.0 "net.mamoe:mirai-console-terminal" v2.11.0 "net.mamoe:mirai-core-all" v2.11.0 "org.itxtech:mcl-addon" v2.0.2 "org.bouncycastle:bcprov-jdk15on" v1.64 "net.mamoe:mirai-api-http" v2.5.2 "net.mamoe:chat-command" v0.5.1 "xyz.cssxsh.mirai:mirai-administrator" v1.1.0 "xyz.cssxsh.mirai:mirai-administrator" has newer version "1.2.0"
系统日志
No response
网络日志
No response
补充信息
Caused by: net.mamoe.yamlkt.YamlDecodingException: Top-level decoder: Yaml Null: Unexpected null
messageChain: null
^ at line 5, column 23
你需要声明类型为可空
public final Value<Map<String , Map<String, String>>> sessionlist = typedValue("sessionlist",
createKType(Map.class,
createKType(String.class),
createKType(Map.class,
createKType(String.class), createKType(String.class, /* nullable */ true)
)
));
试了下,用了nullable: true,该Test非首次运行依然无法通过
public class MockAutoSaveDataTest {
public static class MockPlugin extends JavaPlugin {
public static final MockPlugin INSTANCE = new MockPlugin();
public MockPlugin() {
super(new JvmPluginDescriptionBuilder("org.test.test", "1.0.0").build());
}
}
public static class MockAutoSaveData extends JavaAutoSavePluginConfig {
public static final MockAutoSaveData INSTANCE = new MockAutoSaveData();
public MockAutoSaveData() {
super("MockAutoSaveData");
}
public final Value<Map<String, String>> content = typedValue("content",
createKType(Map.class,
createKType(String.class),
createKType(String.class, true)
)
);
}
@Before
public void beforeTest() {
MiraiConsoleTerminalLoader.INSTANCE.startAsDaemon(new MiraiConsoleImplementationTerminal());
PluginManager.INSTANCE.loadPlugin(MockPlugin.INSTANCE);
PluginManager.INSTANCE.enablePlugin(MockPlugin.INSTANCE);
}
@Test
public void testData() {
MockPlugin.INSTANCE.reloadPluginData(MockAutoSaveData.INSTANCE);
/*
1. 首次运行,yml文件生成内容为“content: {}”,通过测试
2. 人工编辑yml文件内容为“
content:
foo: null
”时,也应能通过测试
*/
assertEquals(null, MockAutoSaveData.INSTANCE.content.get().get("foo"));
}
}
> Task :test
Top-level decoder: deserializing nested class for 'content' in 'MockAutoSaveData'
foo: null
^ at line 2, column 12
net.mamoe.yamlkt.YamlDecodingException: Top-level decoder: deserializing nested class for 'content' in 'MockAutoSaveData'
foo: null
^ at line 2, column 12
at net.mamoe.yamlkt.internal.YamlUtils__ContextualExceptionKt.contextualDecodingException(ContextualException.kt:154)
at net.mamoe.yamlkt.internal.YamlUtils.contextualDecodingException(Unknown Source)
at net.mamoe.yamlkt.internal.YamlDecoder$AbstractDecoder.decodeSerializableElement(YamlDecoder.kt:181)
at kotlinx.serialization.encoding.CompositeDecoder$DefaultImpls.decodeSerializableElement$default(Decoding.kt:535)
at net.mamoe.mirai.console.internal.data.PluginDataImpl$updaterSerializer$1.deserialize(PluginDataImpl.kt:85)
at net.mamoe.mirai.console.internal.data.PluginDataImpl$updaterSerializer$1.deserialize(PluginDataImpl.kt:47)
at net.mamoe.yamlkt.Yaml.decodeFromString(Yaml.kt:162)
at net.mamoe.mirai.console.internal.data.MultiFilePluginDataStorageImpl.load(MultiFilePluginDataStorageImpl.kt:40)
at net.mamoe.mirai.console.plugin.jvm.AbstractJvmPlugin.reloadPluginData(AbstractJvmPlugin.kt:50)
at org.example.mirai.plugin.MockAutoSaveDataTest.testData(MockAutoSaveDataTest.java:50)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:119)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method net.mamoe.mirai.console.internal.data.StringValueImpl.setValue, parameter v
at net.mamoe.mirai.console.internal.data.StringValueImpl.setValue(_PrimitiveValueDeclarations.kt)
at net.mamoe.mirai.console.internal.data.StringValueImpl.set(_PrimitiveValueDeclarations.kt:348)
at net.mamoe.mirai.console.data.PluginDataKt.valueFromKType(PluginData.kt:332)
at net.mamoe.mirai.console.internal.data.ValueFromKTypeImplKt$valueFromKTypeImpl$3.invoke(valueFromKTypeImpl.kt:70)
at net.mamoe.mirai.console.internal.data.ValueFromKTypeImplKt$valueFromKTypeImpl$3.invoke(valueFromKTypeImpl.kt:61)
at net.mamoe.mirai.console.internal.data.ShadowMap.putAll(collectionUtil.kt:86)
at net.mamoe.mirai.console.internal.data.CollectionUtilKt$observable$ObservableMap.putAll(collectionUtil.kt:400)
at net.mamoe.mirai.console.internal.data.CompositeValueImplKt.patchImpl(CompositeValueImpl.kt:190)
at net.mamoe.mirai.console.internal.data.CompositeValueImplKt.tryPatch(CompositeValueImpl.kt:208)
at net.mamoe.mirai.console.internal.data.CompositeMapValueImpl.setValueBySerializer(CompositeValueImpl.kt:157)
at net.mamoe.mirai.console.internal.data.CompositeMapValueImpl.setValueBySerializer(CompositeValueImpl.kt:127)
at net.mamoe.mirai.console.internal.data._PrimitiveValueDeclarationsKt.setValueBySerializer(_PrimitiveValueDeclarations.kt:32)
at net.mamoe.mirai.console.data.SerializableValue$Companion$serializableValueWith$$inlined$map$1.deserialize(serializerHelper.kt:175)
at net.mamoe.yamlkt.internal.YamlDecoder$AbstractDecoder.decodeSerializableElement(YamlDecoder.kt:179)
... 55 more
或者test2()
@Test
public void testData2() {
MockPlugin.INSTANCE.reloadPluginData(MockAutoSaveData.INSTANCE);
/*
不论是否首次运行,尝试写入null map-value
*/
Map<String, String> nullValueMap = new HashMap<>();
nullValueMap.put("foo", null);
MockAutoSaveData.INSTANCE.content.set(nullValueMap);
// assert 方法正常结束
}
也是出现
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method net.mamoe.mirai.console.internal.data.StringValueImpl.setValue, parameter v
at net.mamoe.mirai.console.internal.data.StringValueImpl.setValue(_PrimitiveValueDeclarations.kt)
at net.mamoe.mirai.console.internal.data.StringValueImpl.set(_PrimitiveValueDeclarations.kt:348)
我们还没支持在map/set等里面使用可空类型
那确实是得支持的