You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Magnolia中如何正确读取单值与多值JCR属性?

如何在Magnolia中正确读取同时存在单值与多值的JCR属性?

问题描述

我在Magnolia中尝试读取节点属性时,因为把多值属性直接赋值给String类型触发了错误,想请教如何同时正确处理单值和多值属性。

报错信息

javax.jcr.ValueFormatException: property /wcmstest/de/search/jcr:mixinTypes is a multi-valued property, so it's values can only be retrieved as an array
	at org.apache.jackrabbit.core.PropertyImpl.internalGetValue(PropertyImpl.java:483)
	at org.apache.jackrabbit.core.PropertyImpl.getValue(PropertyImpl.java:510)
	at org.apache.jackrabbit.core.PropertyImpl.getString(PropertyImpl.java:520)
	at info.magnolia.jcr.wrapper.DelegatePropertyWrapper.getString(DelegatePropertyWrapper.java:162)
	at info.magnolia.jcr.wrapper.DelegatePropertyWrapper.getString(DelegatePropertyWrapper.java:162)
	at info.magnolia.jcr.wrapper.DelegatePropertyWrapper.getString(DelegatePropertyWrapper.java:162)
	at info.magnolia.jcr.wrapper.DelegatePropertyWrapper.getString(DelegatePropertyWrapper.java:162)
	at info.magnolia.jcr.wrapper.DelegatePropertyWrapper.getString(DelegatePropertyWrapper.java:162)
	at ch.uzh.module.versioning.CreateNestedMap.nestedMap(CreateNestedMap.java:32)
	at ch.uzh.module.versioning.ContextLoggerCommand.execute(ContextLoggerCommand.java:78)
	at info.magnolia.commands.MgnlCommand.executeSynchronized(MgnlCommand.java:80)
	at info.magnolia.commands.MgnlCommand.execute(MgnlCommand.java:69)
	at info.magnolia.commands.chain.ChainBase.execute(ChainBase.java:101)
	at info.magnolia.commands.DelegateCommand.execute(DelegateCommand.java:66)

原代码

HashMap<String, Object> map = new LinkedHashMap<>();
PropertyIterator pi;
try {
    pi = node.getProperties(); //获取根节点的属性
    while(pi.hasNext()) {
        Property p = pi.nextProperty();
        String name = p.getName();
        String val = p.getString();
        map.put(name,val);
    }//结束根节点属性遍历
} catch (RepositoryException e) {
    // TODO 自动生成的捕获块
    e.printStackTrace();
}

解决方案

这个问题其实是JCR(Java Content Repository)规范里的常见坑——单值和多值属性的读取API是分开的,你直接用getString()读取多值属性肯定会触发ValueFormatException,下面给你具体的解决方法:

核心思路

先通过isMultiple()方法判断属性是单值还是多值,再分别调用对应API读取:

  • 单值属性:用getString()直接读取
  • 多值属性:用getValues()获取Value数组,再转换为字符串集合存入Map

修改后的代码示例

HashMap<String, Object> map = new LinkedHashMap<>();
PropertyIterator pi;
try {
    pi = node.getProperties(); // 获取根节点的属性
    while (pi.hasNext()) {
        Property p = pi.nextProperty();
        String name = p.getName();
        
        if (p.isMultiple()) {
            // 处理多值属性:转换为字符串列表
            List<String> values = new ArrayList<>();
            for (Value value : p.getValues()) {
                values.add(value.getString());
            }
            map.put(name, values);
        } else {
            // 处理单值属性
            String val = p.getString();
            map.put(name, val);
        }
    } // 结束根节点属性遍历
} catch (RepositoryException e) {
    e.printStackTrace();
}

额外优化建议

如果你希望后续处理更统一,也可以把单值属性包装成只有一个元素的列表,让Map的value类型统一为List<String>,代码调整如下:

// 统一为List<String>类型的value
HashMap<String, List<String>> map = new LinkedHashMap<>();
// ...
if (p.isMultiple()) {
    List<String> values = new ArrayList<>();
    for (Value value : p.getValues()) {
        values.add(value.getString());
    }
    map.put(name, values);
} else {
    map.put(name, Collections.singletonList(p.getString()));
}

内容的提问来源于stack exchange,提问作者Ana Sustic

火山引擎 最新活动