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




