Datatables — это плагин jquery для представления табличной информации — он может улучшать простую таблицу или использовать данные на основе AJAX и представлять информацию в табличной форме.
Datatables требует, чтобы данные с сервера следовали определенному формату JSON, чтобы они отображались на экране. Рассмотрим случай, когда должен отображаться список сущностей членов, ожидаемая структура json для членов должна быть такой:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
{ 'aaData':[ { 'id':1, 'first':'one', 'last':'one', 'addresses':[ ], 'version':0 }, { 'id':2, 'first':'two', 'last':'two', 'addresses':[ ], 'version':0 } ], 'iTotalRecords':100, 'iTotalDisplayRecords':10, 'success':true} |
Может быть определен универсальный тип Java, который Джексон может использовать для генерации json типа, показанного выше, рассмотрим следующий универсальный тип Java:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package mvcsample.types;import java.util.List;public class ListWrapper<T> { private List<T> aaData; private int iTotalRecords; private int iTotalDisplayRecords; private Boolean success; public List<T> getAaData() { return aaData; } public void setAaData(List<T> aaData) { this.aaData = aaData; } public int getiTotalRecords() { return iTotalRecords; } public void setiTotalRecords(int iTotalRecords) { this.iTotalRecords = iTotalRecords; } public int getiTotalDisplayRecords() { return iTotalDisplayRecords; } public void setiTotalDisplayRecords(int iTotalDisplayRecords) { this.iTotalDisplayRecords = iTotalDisplayRecords; } public Boolean getSuccess() { return success; } public void setSuccess(Boolean success) { this.success = success; } } |
Итак, с этим универсальным типом, для генерации списка членов у меня будет параметризованный тип, определенный как в этом тесте:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
List<Member> members = new ArrayList<>();members.add(new Member('one', 'one'));members.add(new Member('two', 'two'));ListWrapper<Member> membersWrapper = new ListWrapper<>();membersWrapper.setAaData(members);membersWrapper.setiTotalDisplayRecords(10);membersWrapper.setiTotalRecords(100);ObjectMapper objectMapper = new ObjectMapper();StringWriter w = new StringWriter();objectMapper.writeValue(w, membersWrapper);String json = w.toString();System.out.println(json); |
Аналогичным образом может быть сгенерирован json для любого другого типа.
Тем не менее, как же наоборот, генерируя тип Java с учетом json.
Опять же, рассмотрим случай, когда указанный в начале json должен быть преобразован в ListWrapper <Member>, я могу попробовать десериализацию следующим образом:
|
1
2
|
ObjectMapper objectMapper = new ObjectMapper(); ListWrapper<Member> membersUpdated = objectMapper.readValue(json, ListWrapper.class); |
Обратите внимание, что выше я не могу ссылаться на тип класса как ListWrapper <Member> .class, я могу только ссылаться на него как ListWrapper.class.
Это, однако, не будет работать, и результирующий тип не будет оберткой вокруг класса Member, так как во время выполнения Джексон не подозревает, что ему нужно сгенерировать ListWrapper <Member>.
Исправление заключается в том, чтобы каким-то образом передать информацию о типе ListWrapper Джексону, и именно здесь в него помещаются токены типа Super . В статье объясняется, как это работает очень подробно, суть в том, что в то время как стирание типа действительно удаляет информацию о типе из параметризованных экземпляров универсальный тип, однако тип сохраняется в подклассах универсальных классов.
Например, Рассмотрим следующий класс StringList, производный от ArrayList <String>, можно обнаружить, что параметром типа базового класса является String, как показано в тесте ниже:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.ArrayList;public class StringList extends ArrayList<String>{ public static void main(String[] args) { StringList list = new StringList(); Type superClassType = list.getClass().getGenericSuperclass(); ParameterizedType parameterizedType = (ParameterizedType)superClassType; System.out.println(parameterizedType.getActualTypeArguments()[0]); }} |
Это применимо для случая, когда подкласс определяется как анонимный класс также следующим образом:
|
1
2
3
4
|
ArrayList<String> list = new ArrayList<String>(){};Type superClassType = list.getClass().getGenericSuperclass();ParameterizedType parameterizedType = (ParameterizedType)superClassType;System.out.println(parameterizedType.getActualTypeArguments()[0]); |
Это то, что используется внутри шаблона токенов Super Type для поиска типа параметризованного типа. Абстрактный класс Джексона com.fasterxml.jackson.core.type.TypeReference реализует это, и с помощью этого десериализация Джексона будет работать следующим образом:
|
1
2
3
4
5
6
|
import com.fasterxml.jackson.core.type.TypeReference;....ListWrapper<Member> membersWrapper = objectMapper.readValue(json, new TypeReference<ListWrapper<Member>>() {});ListWrapper<Address> addressWrapper = objectMapper.readValue(json, new TypeReference<ListWrapper<Address>>() {}); |
Таким образом, два различных параметризованных типа могут быть десериализованы с использованием универсального типа и представления json.
Ресурсы:
- Отражение родовых : http://www.artima.com/weblogs/viewpost.jsp?thread=208860
- Супер-токены Нила Гэфтера: http://gafter.blogspot.com/2006/12/super-type-tokens.html
Ссылка: десериализация Json с помощью токенов типа Джексона и Super от нашего партнера JCG Биджу Кунджуммена в блоге all and sundry.