001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.json.jabsorb.serializer;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.ClassResolverUtil;
020    
021    import java.io.Serializable;
022    
023    import java.lang.reflect.Constructor;
024    import java.lang.reflect.Field;
025    import java.lang.reflect.Modifier;
026    
027    import java.util.HashSet;
028    import java.util.Iterator;
029    import java.util.Set;
030    
031    import org.jabsorb.JSONSerializer;
032    import org.jabsorb.serializer.AbstractSerializer;
033    import org.jabsorb.serializer.MarshallException;
034    import org.jabsorb.serializer.ObjectMatch;
035    import org.jabsorb.serializer.SerializerState;
036    import org.jabsorb.serializer.UnmarshallException;
037    
038    import org.json.JSONObject;
039    
040    /**
041     * @author Raymond Aug??
042     */
043    public class LiferaySerializer extends AbstractSerializer {
044    
045            @Override
046            public boolean canSerialize(
047                    @SuppressWarnings("rawtypes") Class clazz,
048                    @SuppressWarnings("rawtypes") Class jsonClass) {
049    
050                    Constructor<?> constructor = null;
051    
052                    try {
053                            constructor = clazz.getConstructor();
054                    }
055                    catch (Exception e) {
056                    }
057    
058                    if (Serializable.class.isAssignableFrom(clazz) &&
059                            ((jsonClass == null) || (jsonClass == JSONObject.class)) &&
060                            (constructor != null)) {
061    
062                            return true;
063                    }
064    
065                    return false;
066            }
067    
068            @Override
069            public Class<?>[] getJSONClasses() {
070                    return _JSON_CLASSES;
071            }
072    
073            @Override
074            public Class<?>[] getSerializableClasses() {
075                    return _SERIALIZABLE_CLASSES;
076            }
077    
078            @Override
079            public Object marshall(
080                            SerializerState serializerState, Object parentObject, Object object)
081                    throws MarshallException {
082    
083                    JSONObject jsonObject = new JSONObject();
084    
085                    Class<?> javaClass = object.getClass();
086    
087                    if (ser.getMarshallClassHints()) {
088                            try {
089                                    jsonObject.put("javaClass", javaClass.getName());
090                            }
091                            catch (Exception e) {
092                                    throw new MarshallException("Unable to put javaClass", e);
093                            }
094                    }
095    
096                    JSONObject serializableJSONObject = new JSONObject();
097    
098                    try {
099                            jsonObject.put("serializable", serializableJSONObject);
100    
101                            serializerState.push(
102                                    object, serializableJSONObject, "serializable");
103                    }
104                    catch (Exception e) {
105                            throw new MarshallException("Unable to put serializable", e);
106                    }
107    
108                    String fieldName = null;
109    
110                    try {
111                            Set<String> processedFieldNames = new HashSet<String>();
112    
113                            while (javaClass != null) {
114                                    Field[] declaredFields = javaClass.getDeclaredFields();
115    
116                                    for (Field field : declaredFields) {
117                                            fieldName = field.getName();
118    
119                                            // Avoid processing overridden fields of super classes
120    
121                                            if (processedFieldNames.contains(fieldName)) {
122                                                    continue;
123                                            }
124    
125                                            processedFieldNames.add(fieldName);
126    
127                                            int modifiers = field.getModifiers();
128    
129                                            // Only marshall fields that are not final, static, or
130                                            // transient
131    
132                                            if (((modifiers & Modifier.FINAL) == Modifier.FINAL) ||
133                                                    ((modifiers & Modifier.STATIC) == Modifier.STATIC) ||
134                                                    ((modifiers & Modifier.TRANSIENT) ==
135                                                            Modifier.TRANSIENT)) {
136    
137                                                    continue;
138                                            }
139    
140                                            if (!field.isAccessible()) {
141                                                    field.setAccessible(true);
142                                            }
143    
144                                            if (fieldName.startsWith("_")) {
145                                                    fieldName = fieldName.substring(1);
146                                            }
147    
148                                            Object fieldObject = ser.marshall(
149                                                    serializerState, serializableJSONObject,
150                                                    field.get(object), fieldName);
151    
152                                            // Omit the object entirely if it is a circular reference or
153                                            // duplicate. It will be regenerated in the fixups phase.
154    
155                                            if (JSONSerializer.CIRC_REF_OR_DUPLICATE != fieldObject) {
156                                                    serializableJSONObject.put(fieldName, fieldObject);
157                                            }
158                                    }
159    
160                                    javaClass = javaClass.getSuperclass();
161                            }
162                    }
163                    catch (Exception e) {
164                            throw new MarshallException(
165                                    "Unable to match field " + fieldName, e);
166                    }
167                    finally {
168                            serializerState.pop();
169                    }
170    
171                    return jsonObject;
172            }
173    
174            @Override
175            public ObjectMatch tryUnmarshall(
176                            SerializerState serializerState,
177                            @SuppressWarnings("rawtypes") Class clazz, Object object)
178                    throws UnmarshallException {
179    
180                    JSONObject jsonObject = (JSONObject)object;
181    
182                    String javaClassName = null;
183    
184                    try {
185                            javaClassName = jsonObject.getString("javaClass");
186                    }
187                    catch (Exception e) {
188                            throw new UnmarshallException("Unable to get javaClass", e);
189                    }
190    
191                    if (javaClassName == null) {
192                            throw new UnmarshallException("javaClass is undefined");
193                    }
194    
195                    try {
196                            Class<?> javaClass = ClassResolverUtil.resolveByContextClassLoader(
197                                    javaClassName);
198    
199                            Serializable.class.isAssignableFrom(javaClass);
200                    }
201                    catch (Exception e) {
202                            throw new UnmarshallException(
203                                    "Unable to load javaClass " + javaClassName, e);
204                    }
205    
206                    JSONObject serializableJSONObject = null;
207    
208                    try {
209                            serializableJSONObject = jsonObject.getJSONObject("serializable");
210                    }
211                    catch (Exception e) {
212                            throw new UnmarshallException("Unable to get serializable", e);
213                    }
214    
215                    if (serializableJSONObject == null) {
216                            throw new UnmarshallException("serializable is undefined");
217                    }
218    
219                    ObjectMatch objectMatch = new ObjectMatch(-1);
220    
221                    serializerState.setSerialized(object, objectMatch);
222    
223                    String fieldName = null;
224    
225                    try {
226                            Iterator<?> iterator = serializableJSONObject.keys();
227    
228                            while (iterator.hasNext()) {
229                                    fieldName = (String)iterator.next();
230    
231                                    ObjectMatch fieldObjectMatch = ser.tryUnmarshall(
232                                            serializerState, null,
233                                            serializableJSONObject.get(fieldName));
234    
235                                    ObjectMatch maxFieldObjectMatch = fieldObjectMatch.max(
236                                            objectMatch);
237    
238                                    objectMatch.setMismatch(maxFieldObjectMatch.getMismatch());
239                            }
240                    }
241                    catch (Exception e) {
242                            throw new UnmarshallException(
243                                    "Unable to match field " + fieldName, e);
244                    }
245    
246                    return objectMatch;
247            }
248    
249            @Override
250            public Object unmarshall(
251                            SerializerState serializerState,
252                            @SuppressWarnings("rawtypes") Class clazz, Object object)
253                    throws UnmarshallException {
254    
255                    JSONObject jsonObject = (JSONObject)object;
256    
257                    String javaClassName = null;
258    
259                    try {
260                            javaClassName = jsonObject.getString("javaClass");
261                    }
262                    catch (Exception e) {
263                            throw new UnmarshallException("Unable to get javaClass", e);
264                    }
265    
266                    if (javaClassName == null) {
267                            throw new UnmarshallException("javaClass is undefined");
268                    }
269    
270                    Class<?> javaClass = null;
271    
272                    Object javaClassInstance = null;
273    
274                    try {
275                            javaClass = ClassResolverUtil.resolveByContextClassLoader(
276                                    javaClassName);
277    
278                            javaClassInstance = javaClass.newInstance();
279                    }
280                    catch (Exception e) {
281                            throw new UnmarshallException(
282                                    "Unable to load javaClass " + javaClassName, e);
283                    }
284    
285                    JSONObject serializableJSONObject = null;
286    
287                    try {
288                            serializableJSONObject = jsonObject.getJSONObject("serializable");
289                    }
290                    catch (Exception e) {
291                            throw new UnmarshallException("Unable to get serializable", e);
292                    }
293    
294                    if (serializableJSONObject == null) {
295                            throw new UnmarshallException("serializable is undefined");
296                    }
297    
298                    serializerState.setSerialized(object, javaClassInstance);
299    
300                    String fieldName = null;
301    
302                    try {
303                            Set<String> processedFieldNames = new HashSet<String>();
304    
305                            while (javaClass != null) {
306                                    Field[] fields = javaClass.getDeclaredFields();
307    
308                                    for (Field field : fields) {
309                                            fieldName = field.getName();
310    
311                                            // Avoid processing overridden fields of super classes
312    
313                                            if (processedFieldNames.contains(fieldName)) {
314                                                    continue;
315                                            }
316    
317                                            processedFieldNames.add(fieldName);
318    
319                                            int modifiers = field.getModifiers();
320    
321                                            // Only unmarshall fields that are not final, static, or
322                                            // transient
323    
324                                            if (((modifiers & Modifier.FINAL) == Modifier.FINAL) ||
325                                                    ((modifiers & Modifier.STATIC) == Modifier.STATIC) ||
326                                                    ((modifiers & Modifier.TRANSIENT) ==
327                                                            Modifier.TRANSIENT)) {
328    
329                                                    continue;
330                                            }
331    
332                                            if (!field.isAccessible()) {
333                                                    field.setAccessible(true);
334                                            }
335    
336                                            if (fieldName.startsWith("_")) {
337                                                    fieldName = fieldName.substring(1);
338                                            }
339    
340                                            Object value = null;
341    
342                                            try {
343                                                    value = ser.unmarshall(
344                                                            serializerState, field.getType(),
345                                                            serializableJSONObject.get(fieldName));
346                                            }
347                                            catch (Exception e) {
348                                            }
349    
350                                            if (value != null) {
351                                                    try {
352                                                            field.set(javaClassInstance, value);
353                                                    }
354                                                    catch (Exception e) {
355                                                            _log.error(e, e);
356                                                    }
357                                            }
358                                    }
359    
360                                    javaClass = javaClass.getSuperclass();
361                            }
362                    }
363                    catch (Exception e) {
364                            throw new UnmarshallException(
365                                    "Unable to match field " + fieldName, e);
366                    }
367    
368                    return javaClassInstance;
369            }
370    
371            private static final Class<?>[] _JSON_CLASSES = {JSONObject.class};
372    
373            private static final Class<?>[] _SERIALIZABLE_CLASSES =
374                    {Serializable.class};
375    
376            private static Log _log = LogFactoryUtil.getLog(LiferaySerializer.class);
377    
378    }