Я пытаюсь преобразовать простой массив строковых элементов в документе json в список java, который находится внутри компонента с использованием genson. Я ожидал, что это произойдет автоматически, но это не работает. Я что-то упускаю?
Вот моя 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 в объект списка java, находящийся внутри компонента?
РЕДАКТИРОВАТЬ [РЕШЕНО ЧАСТИЧНО - ЕЩЕ ОДИН ВОПРОС ОТКРЫТ]
Теперь у меня есть шаг вперед. Я вернулся к истокам и начал с простого bean-компонента, который просто содержит список строк. И, как и ожидалось в первый раз, это работает. Разница между предыдущим объектом в основном в том, что этот следует спецификации bean-компонента. Другой объект (DefaultRole) следует шаблону текучего объекта (не уверен, что это правильное определение). По сути, вместо того, чтобы метод setter был пустым, я возвращаю объект, так что следующее значение можно легко установить плавным образом.
Итак, это работает:
public void setPermissions(List<String> permissions)
{
this.permissions = permissions;
}
Это не работает:
public Role setPermissions(List<String> permissions)
{
this.permissions = permissions;
return this;
}
Кто-нибудь еще сталкивался с этим и каковы альтернативы переключению всех моих bean-компонентов на соответствие спецификации bean-компонентов? Является ли единственным вариантом использовать чистое заполнение на уровне поля вместо метода установки?
РЕДАКТИРОВАТЬ [ПОЧТИ РЕШЕНО]
Привет, я не уверен, как лучше всего отвечать на вопросы, где код необходим, чтобы помочь понять, что я сделал.
В любом случае, большое спасибо за вашу помощь. Мне очень нравится третий вариант, именно его я и искал. К сожалению, теперь я получаю сообщение об ошибке «Не найден конструктор для класса типов 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(метод) выглядит так (код адаптирован отсюда: 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»). Это важно поскольку стандартные Resolvers больше не используются в противном случае, и вы получите ошибку, которая была у меня, когда конструктор больше не может быть найден.
Метод 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].*");
}
Здесь важно отметить, что я изначально использовал «равно» вместо «isAssignableFrom» при сравнении возвращаемого типа с объявляющим классом. Это работает только в том случае, если возвращаемый тип точно такой же, как тот, в котором он объявлен. Однако при использовании интерфейса в качестве возвращаемого значения он больше не работает. Вместо этого с помощью «method.getReturnType().isAssignableFrom(method.getDeclaringClass())» это также работает для интерфейсов (включая суперинтерфейсы).
Спасибо, Майкл