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.