PKL集成Hocon配置:自定义资源读取器如何返回复合结构?
问题
我的项目当前使用Hocon配置,计划逐步迁移至PKL配置框架。为保障过渡阶段顺畅,我希望能在PKL中引用旧配置中的部分值。我尝试通过实现自定义资源读取器来实现该需求,代码如下:
import com.typesafe.config.*; import org.pkl.core.SecurityManagerException; import org.pkl.core.resource.ResourceReader; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Optional; class HoconResourceReader implements ResourceReader { private Config config = ConfigFactory.load(); public Optional<Object> read(URI uri) { if (config.hasPath(uri.getSchemeSpecificPart())) { var value = config.getAnyRef(uri.getSchemeSpecificPart()); return Optional.of(value.toString()); } else { return Optional.empty(); } } public String getUriScheme() { return "hocon"; } public boolean hasHierarchicalUris() { return true; } public boolean isGlobbable() { return true; } }
该读取器可正常处理字符串等标量值,但我需要它支持返回带属性的动态对象这类复合结构。请问是否有办法从自定义值创建此类对象?
回答
要让自定义资源读取器返回PKL的动态对象(适配Hocon复合结构),不能直接返回字符串,需要将Hocon的复合结构递归转换成PKL兼容的DynamicObject实例,具体实现如下:
核心思路
利用Hocon的ConfigValue遍历所有类型的配置节点,递归转换为PKL支持的类型:- 标量值(字符串、数字、布尔、null)直接返回原始Java类型,PKL会自动适配
- Hocon对象(
ConfigObject)通过PKL的DynamicObjects.createObjectBuilder()构建动态对象,逐个添加转换后的属性 - Hocon列表(
ConfigList)转换为Java列表,内部元素递归转换
修改后的完整代码
import com.typesafe.config.*; import org.pkl.core.resource.ResourceReader; import org.pkl.core.util.DynamicObjects; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Optional; class HoconResourceReader implements ResourceReader { private final Config config = ConfigFactory.load(); @Override public Optional<Object> read(URI uri) { String path = uri.getSchemeSpecificPart(); if (!config.hasPath(path)) { return Optional.empty(); } ConfigValue value = config.getValue(path); return Optional.of(convertHoconValueToPkl(value)); } private Object convertHoconValueToPkl(ConfigValue hoconValue) { ConfigValueType type = hoconValue.valueType(); return switch (type) { case OBJECT -> { ConfigObject configObject = (ConfigObject) hoconValue; var builder = DynamicObjects.createObjectBuilder(); configObject.forEach((key, val) -> builder.put(key, convertHoconValueToPkl(val)) ); yield builder.build(); } case LIST -> { ConfigList configList = (ConfigList) hoconValue; List<Object> pklList = new ArrayList<>(); for (ConfigValue item : configList) { pklList.add(convertHoconValueToPkl(item)); } yield pklList; } case STRING, NUMBER, BOOLEAN -> hoconValue.unwrapped(); case NULL -> null; }; } @Override public String getUriScheme() { return "hocon"; } @Override public boolean hasHierarchicalUris() { return true; } @Override public boolean isGlobbable() { return true; } }
- PKL中的使用示例
现在可以直接在PKL配置中引用Hocon的复合结构,比如:
import "hocon:app.database" as dbConfig database { url = dbConfig.url credentials { username = dbConfig.credentials.username password = dbConfig.credentials.password } }
这样修改后,读取器就能正确解析Hocon中的嵌套对象和列表,让你在PKL中直接访问嵌套属性,满足过渡阶段的配置复用需求。
内容的提问来源于stack exchange,提问作者Artem Petrov
相关产品推荐
相关产品推荐

