我正在尝试将 json 文档中的简单字符串元素数组转换为 java 列表,该列表位于使用 genson 的 bean 内。我期待这会自动发生,但它不起作用。我错过了什么吗?
这是我的 Json 字符串:
{"id":12345,"permissions":["READ_XX","WRITE_XX"]}
这是我的对象的输出,表明我的权限列表没有被填充:
DefaultRole [id=12345, name=null, permissions=[]]
我的 DefaultRole 类如下所示:
public class DefaultRole implements Role
{
public Id id = null;
@XmlElementWrapper(name = "permissions")
@XmlElement(name = "permission")
private List<String> permissions = Lists.newArrayList();
@Inject
public DefaultRole()
{
}
[...]
JAXB 注释仅用于 XML 转换。他们不应该在这里发挥作用。
我正在创建这样的 Genson 对象:
Genson genson = new Genson.Builder()
.setWithClassMetadata(false)
.setWithBeanViewConverter(true)
.setWithDebugInfoPropertyNameResolver(true)
.setSkipNull(true)
.create();
我的反序列化调用:
genson().deserialize(jsonString, DefaultRole.class)
有没有人有关于如何将我的 json 字符串数组反序列化为驻留在 bean 内的 java List 对象的提示?
编辑[部分解决-还有一个问题未解决]
我现在更进一步了。我回到根源,从一个简单的包含字符串列表的基本 bean 开始。正如预期的那样,这是第一次。与上一个对象的区别主要是这个遵循bean规范。另一个对象(DefaultRole)遵循流体对象模式(不确定这是否是正确的定义)。基本上,我不是将 setter 方法设为 void,而是返回对象,以便可以轻松地以流畅的方式设置下一个值。
所以这有效:
public void setPermissions(List<String> permissions)
{
this.permissions = permissions;
}
这不起作用:
public Role setPermissions(List<String> permissions)
{
this.permissions = permissions;
return this;
}
有没有其他人遇到过这种情况,以及将我所有的 bean 转换为遵守 bean 规范的替代方法是什么?是使用纯字段级填充而不是通过 setter 方法的唯一选择吗?
编辑[几乎解决]
嗨,我不确定如何最好地回答需要代码来帮助理解我所做的问题。
无论如何,非常感谢您的帮助。我真的很喜欢第三个选项,这是我一直在寻找的类型。不幸的是,我现在收到错误“没有找到类型类 xxx.DefaultRole 的构造函数”。根据您在回答中所说的,当搜索继续时返回 Trilean.UNKNOWN 时不应该发生这种情况。
我将以下代码添加到我的 genson-builder 中:
.set(new BeanMutatorAccessorResolver.BaseResolver()
{
@Override
public Trilean isMutator(Method method, Class<?> fromClass)
{
if (Reflect.isSetter(method))
return Trilean.TRUE;
else
return Trilean.UNKNOWN;
}
})
我的 Reflect.isSetter(method) 看起来像这样(代码改编自这里:http ://www.asgteach.com/blog/?p=559 ):
public static boolean isSetter(Method method)
{
return Modifier.isPublic(method.getModifiers()) &&
(method.getReturnType().equals(void.class) || method.getReturnType().equals(method.getDeclaringClass())) &&
method.getParameterTypes().length == 1 &&
method.getName().matches("^set[A-Z].*");
}
BaseResolver 为尚未实现的所有内容返回 Trilean.UNKNOWN。因此它应该使用标准逻辑找到构造函数,不是吗?
编辑[已解决]
为了完整起见,我将发布实际有效的代码:
public static final Genson genson()
{
Genson genson = new Genson.Builder()
.setSkipNull(true)
.setWithClassMetadata(false)
.setWithDebugInfoPropertyNameResolver(true)
.setWithBeanViewConverter(true)
.with(new BeanMutatorAccessorResolver.BaseResolver()
{
@Override
public Trilean isMutator(Method method, Class<?> fromClass)
{
if (Reflect.isSetter(method))
return Trilean.TRUE;
else
return Trilean.UNKNOWN;
}
})
.create();
return genson;
}
需要注意的是,“.set(new BeanMutatorAccessorResolver.BaseResolver()”必须替换为“.with(new BeanMutatorAccessorResolver.BaseResolver()”(注意“with”而不是“set”)。这很重要因为不再使用标准解析器,否则您最终会遇到我遇到的错误,无法再找到构造函数。
isSetter 方法如下所示:
public static boolean isSetter(Method method)
{
return Modifier.isPublic(method.getModifiers())
&& (method.getReturnType().equals(void.class) || method.getReturnType().isAssignableFrom(method.getDeclaringClass()))
&& method.getParameterTypes().length == 1
&& method.getName().matches("^set[A-Z].*");
}
这里需要注意的是,在将返回类型与声明类进行比较时,我最初使用的是“equals”而不是“isAssignableFrom”。这只适用于返回类型与声明它的类完全相同的类。当使用接口作为返回值时,它不再起作用。通过使用“method.getReturnType().isAssignableFrom(method.getDeclaringClass())”,这也适用于接口(包括超级接口)。
谢谢,迈克尔