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