1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.primefaces.extensions.converter;
23
24 import java.io.Serializable;
25 import java.lang.reflect.Array;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.el.ValueExpression;
32 import javax.faces.application.FacesMessage;
33 import javax.faces.component.UIComponent;
34 import javax.faces.context.FacesContext;
35 import javax.faces.convert.Converter;
36 import javax.faces.convert.ConverterException;
37 import javax.faces.convert.FacesConverter;
38
39 import org.primefaces.extensions.util.ExtLangUtils;
40 import org.primefaces.extensions.util.json.GsonConverter;
41 import org.primefaces.extensions.util.json.ParameterizedTypeImpl;
42 import org.primefaces.util.Constants;
43
44
45
46
47
48
49
50
51 @FacesConverter(value = "org.primefaces.extensions.converter.JsonConverter")
52 public class JsonConverter implements Converter, Serializable {
53
54 private static final long serialVersionUID = 20121214L;
55
56 private static final Map<String, Class<?>> PRIMITIVE_CLASSES = new HashMap<>();
57 private static final Map<String, Class<?>> PRIMITIVE_ARRAY_CLASSES = new HashMap<>();
58
59 static {
60 PRIMITIVE_CLASSES.put("boolean", boolean.class);
61 PRIMITIVE_CLASSES.put("byte", byte.class);
62 PRIMITIVE_CLASSES.put("short", short.class);
63 PRIMITIVE_CLASSES.put("char", char.class);
64 PRIMITIVE_CLASSES.put("int", int.class);
65 PRIMITIVE_CLASSES.put("long", long.class);
66 PRIMITIVE_CLASSES.put("float", float.class);
67 PRIMITIVE_CLASSES.put("double", double.class);
68
69 PRIMITIVE_ARRAY_CLASSES.put("boolean[]", boolean[].class);
70 PRIMITIVE_ARRAY_CLASSES.put("byte[]", byte[].class);
71 PRIMITIVE_ARRAY_CLASSES.put("short[]", short[].class);
72 PRIMITIVE_ARRAY_CLASSES.put("char[]", char[].class);
73 PRIMITIVE_ARRAY_CLASSES.put("int[]", int[].class);
74 PRIMITIVE_ARRAY_CLASSES.put("long[]", long[].class);
75 PRIMITIVE_ARRAY_CLASSES.put("float[]", float[].class);
76 PRIMITIVE_ARRAY_CLASSES.put("double[]", double[].class);
77 }
78
79 private String type;
80
81 @Override
82 public Object getAsObject(FacesContext context, UIComponent component, String value) {
83 java.lang.reflect.Type objType;
84
85 if (getType() == null) {
86 final ValueExpression expression = component.getValueExpression("value");
87 objType = expression.getType(context.getELContext());
88 }
89 else {
90 objType = getObjectType(getType().trim(), false);
91 }
92
93 return GsonConverter.getGson().fromJson(value, objType);
94 }
95
96 @Override
97 public String getAsString(FacesContext context, UIComponent component, Object value) {
98 if (getType() == null) {
99 return GsonConverter.getGson().toJson(value);
100 }
101 else {
102 return GsonConverter.getGson().toJson(value, getObjectType(getType().trim(), false));
103 }
104 }
105
106 protected java.lang.reflect.Type getObjectType(String type, boolean isTypeArg) {
107 Class clazz = PRIMITIVE_CLASSES.get(type);
108 if (clazz != null) {
109 if (!isTypeArg) {
110 return clazz;
111 }
112 else {
113 throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
114 "Type argument can not be a primitive type, but it was " + type
115 + ".",
116 Constants.EMPTY_STRING));
117 }
118 }
119
120 clazz = PRIMITIVE_ARRAY_CLASSES.get(type);
121 if (clazz != null) {
122 return clazz;
123 }
124
125 final int arrayBracketIdx = type.indexOf('[');
126 final int leftBracketIdx = type.indexOf('<');
127 if (arrayBracketIdx >= 0 && (leftBracketIdx < 0 || arrayBracketIdx < leftBracketIdx)) {
128
129 try {
130 clazz = Class.forName(type.substring(0, arrayBracketIdx));
131
132 return Array.newInstance(clazz, 0).getClass();
133 }
134 catch (final ClassNotFoundException e) {
135 throw notFoundException(type.substring(0, arrayBracketIdx));
136 }
137 }
138
139 if (leftBracketIdx < 0) {
140 try {
141 return Class.forName(type);
142 }
143 catch (final ClassNotFoundException e) {
144 throw notFoundException(type);
145 }
146 }
147
148 final int rightBracketIdx = type.lastIndexOf('>');
149 if (rightBracketIdx < 0) {
150 throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, type + " is not a valid generic type.",
151 Constants.EMPTY_STRING));
152 }
153
154 Class rawType;
155 try {
156 rawType = Class.forName(type.substring(0, leftBracketIdx));
157 }
158 catch (final ClassNotFoundException e) {
159 throw notFoundException(type.substring(0, leftBracketIdx));
160 }
161
162 final String strTypeArgs = type.substring(leftBracketIdx + 1, rightBracketIdx);
163 final List<String> listTypeArgs = new ArrayList<>();
164 int startPos = 0;
165 int seekPos = 0;
166
167 while (true) {
168 final int commaPos = strTypeArgs.indexOf(',', seekPos);
169 if (commaPos >= 0) {
170 final String term = strTypeArgs.substring(startPos, commaPos);
171 final int countLeftBrackets = ExtLangUtils.countMatches(term, '<');
172 final int countRightBrackets = ExtLangUtils.countMatches(term, '>');
173 if (countLeftBrackets == countRightBrackets) {
174 listTypeArgs.add(term.trim());
175 startPos = commaPos + 1;
176 }
177
178 seekPos = commaPos + 1;
179 }
180 else {
181 listTypeArgs.add(strTypeArgs.substring(startPos).trim());
182
183 break;
184 }
185 }
186
187 if (listTypeArgs.isEmpty()) {
188 throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, type + " is not a valid generic type.",
189 Constants.EMPTY_STRING));
190 }
191
192 final int size = listTypeArgs.size();
193 final java.lang.reflect.Type[] objectTypes = new java.lang.reflect.Type[size];
194 for (int i = 0; i < size; i++) {
195
196 objectTypes[i] = getObjectType(listTypeArgs.get(i), true);
197 }
198
199 return new ParameterizedTypeImpl(rawType, objectTypes, null);
200 }
201
202 public String getType() {
203 return type;
204 }
205
206 public void setType(String type) {
207 this.type = type;
208 }
209
210 private ConverterException notFoundException(String classType) {
211 return new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
212 "Class " + classType + " not found", Constants.EMPTY_STRING));
213 }
214 }