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            public Class<?>[] getJSONClasses() {
068                    return _JSON_CLASSES;
069            }
070    
071            public Class<?>[] getSerializableClasses() {
072                    return _SERIALIZABLE_CLASSES;
073            }
074    
075            public Object marshall(
076                            SerializerState serializerState, Object parentObject, Object object)
077                    throws MarshallException {
078    
079                    JSONObject jsonObject = new JSONObject();
080    
081                    Class<?> javaClass = object.getClass();
082    
083                    if (ser.getMarshallClassHints()) {
084                            try {
085                                    jsonObject.put("javaClass", javaClass.getName());
086                            }
087                            catch (Exception e) {
088                                    throw new MarshallException("Unable to put javaClass", e);
089                            }
090                    }
091    
092                    JSONObject serializableJSONObject = new JSONObject();
093    
094                    try {
095                            jsonObject.put("serializable", serializableJSONObject);
096    
097                            serializerState.push(
098                                    object, serializableJSONObject, "serializable");
099                    }
100                    catch (Exception e) {
101                            throw new MarshallException("Unable to put serializable", e);
102                    }
103    
104                    String fieldName = null;
105    
106                    try {
107                            Set<String> processedFieldNames = new HashSet<String>();
108    
109                            while (javaClass != null) {
110                                    Field[] declaredFields = javaClass.getDeclaredFields();
111    
112                                    for (Field field : declaredFields) {
113                                            fieldName = field.getName();
114    
115                                            // Avoid processing overridden fields of super classes
116    
117                                            if (processedFieldNames.contains(fieldName)) {
118                                                    continue;
119                                            }
120    
121                                            processedFieldNames.add(fieldName);
122    
123                                            int modifiers = field.getModifiers();
124    
125                                            // Only marshall fields that are not final, static, or
126                                            // transient
127    
128                                            if (((modifiers & Modifier.FINAL) == Modifier.FINAL) ||
129                                                    ((modifiers & Modifier.STATIC) == Modifier.STATIC) ||
130                                                    ((modifiers & Modifier.TRANSIENT) ==
131                                                            Modifier.TRANSIENT)) {
132    
133                                                    continue;
134                                            }
135    
136                                            if (!field.isAccessible()) {
137                                                    field.setAccessible(true);
138                                            }
139    
140                                            if (fieldName.startsWith("_")) {
141                                                    fieldName = fieldName.substring(1);
142                                            }
143    
144                                            Object fieldObject = ser.marshall(
145                                                    serializerState, serializableJSONObject,
146                                                    field.get(object), fieldName);
147    
148                                            // Omit the object entirely if it is a circular reference or
149                                            // duplicate. It will be regenerated in the fixups phase.
150    
151                                            if (JSONSerializer.CIRC_REF_OR_DUPLICATE != fieldObject) {
152                                                    serializableJSONObject.put(fieldName, fieldObject);
153                                            }
154                                    }
155    
156                                    javaClass = javaClass.getSuperclass();
157                            }
158                    }
159                    catch (Exception e) {
160                            throw new MarshallException(
161                                    "Unable to match field " + fieldName, e);
162                    }
163                    finally {
164                            serializerState.pop();
165                    }
166    
167                    return jsonObject;
168            }
169    
170            public ObjectMatch tryUnmarshall(
171                            SerializerState serializerState,
172                            @SuppressWarnings("rawtypes") Class clazz, Object object)
173                    throws UnmarshallException {
174    
175                    JSONObject jsonObject = (JSONObject)object;
176    
177                    String javaClassName = null;
178    
179                    try {
180                            javaClassName = jsonObject.getString("javaClass");
181                    }
182                    catch (Exception e) {
183                            throw new UnmarshallException("Unable to get javaClass", e);
184                    }
185    
186                    if (javaClassName == null) {
187                            throw new UnmarshallException("javaClass is undefined");
188                    }
189    
190                    try {
191                            Class<?> javaClass = Class.forName(javaClassName);
192    
193                            Serializable.class.isAssignableFrom(javaClass);
194                    }
195                    catch (Exception e) {
196                            throw new UnmarshallException(
197                                    "Unable to load javaClass " + javaClassName, e);
198                    }
199    
200                    JSONObject serializableJSONObject = null;
201    
202                    try {
203                            serializableJSONObject = jsonObject.getJSONObject("serializable");
204                    }
205                    catch (Exception e) {
206                            throw new UnmarshallException("Unable to get serializable", e);
207                    }
208    
209                    if (serializableJSONObject == null) {
210                            throw new UnmarshallException("serializable is undefined");
211                    }
212    
213                    ObjectMatch objectMatch = new ObjectMatch(-1);
214    
215                    serializerState.setSerialized(object, objectMatch);
216    
217                    String fieldName = null;
218    
219                    try {
220                            Iterator<?> iterator = serializableJSONObject.keys();
221    
222                            while (iterator.hasNext()) {
223                                    fieldName = (String)iterator.next();
224    
225                                    ObjectMatch fieldObjectMatch = ser.tryUnmarshall(
226                                            serializerState, null,
227                                            serializableJSONObject.get(fieldName));
228    
229                                    ObjectMatch maxFieldObjectMatch = fieldObjectMatch.max(
230                                            objectMatch);
231    
232                                    objectMatch.setMismatch(maxFieldObjectMatch.getMismatch());
233                            }
234                    }
235                    catch (Exception e) {
236                            throw new UnmarshallException(
237                                    "Unable to match field " + fieldName, e);
238                    }
239    
240                    return objectMatch;
241            }
242    
243            public Object unmarshall(
244                            SerializerState serializerState,
245                            @SuppressWarnings("rawtypes") Class clazz, Object object)
246                    throws UnmarshallException {
247    
248                    JSONObject jsonObject = (JSONObject)object;
249    
250                    String javaClassName = null;
251    
252                    try {
253                            javaClassName = jsonObject.getString("javaClass");
254                    }
255                    catch (Exception e) {
256                            throw new UnmarshallException("Unable to get javaClass", e);
257                    }
258    
259                    if (javaClassName == null) {
260                            throw new UnmarshallException("javaClass is undefined");
261                    }
262    
263                    Class<?> javaClass = null;
264    
265                    Object javaClassInstance = null;
266    
267                    try {
268                            javaClass = Class.forName(javaClassName);
269    
270                            javaClassInstance = javaClass.newInstance();
271                    }
272                    catch (Exception e) {
273                            throw new UnmarshallException(
274                                    "Unable to load javaClass " + javaClassName, e);
275                    }
276    
277                    JSONObject serializableJSONObject = null;
278    
279                    try {
280                            serializableJSONObject = jsonObject.getJSONObject("serializable");
281                    }
282                    catch (Exception e) {
283                            throw new UnmarshallException("Unable to get serializable", e);
284                    }
285    
286                    if (serializableJSONObject == null) {
287                            throw new UnmarshallException("serializable is undefined");
288                    }
289    
290                    serializerState.setSerialized(object, javaClassInstance);
291    
292                    String fieldName = null;
293    
294                    try {
295                            Set<String> processedFieldNames = new HashSet<String>();
296    
297                            while (javaClass != null) {
298                                    Field[] fields = javaClass.getDeclaredFields();
299    
300                                    for (Field field : fields) {
301                                            fieldName = field.getName();
302    
303                                            // Avoid processing overridden fields of super classes
304    
305                                            if (processedFieldNames.contains(fieldName)) {
306                                                    continue;
307                                            }
308    
309                                            processedFieldNames.add(fieldName);
310    
311                                            int modifiers = field.getModifiers();
312    
313                                            // Only unmarshall fields that are not final, static, or
314                                            // transient
315    
316                                            if (((modifiers & Modifier.FINAL) == Modifier.FINAL) ||
317                                                    ((modifiers & Modifier.STATIC) == Modifier.STATIC) ||
318                                                    ((modifiers & Modifier.TRANSIENT) ==
319                                                            Modifier.TRANSIENT)) {
320    
321                                                    continue;
322                                            }
323    
324                                            if (!field.isAccessible()) {
325                                                    field.setAccessible(true);
326                                            }
327    
328                                            if (fieldName.startsWith("_")) {
329                                                    fieldName = fieldName.substring(1);
330                                            }
331    
332                                            Object value = null;
333    
334                                            try {
335                                                    value = ser.unmarshall(
336                                                            serializerState, field.getType(),
337                                                            serializableJSONObject.get(fieldName));
338                                            }
339                                            catch (Exception e) {
340                                            }
341    
342                                            if (value != null) {
343                                                    try {
344                                                            field.set(javaClassInstance, value);
345                                                    }
346                                                    catch (Exception e) {
347                                                            _log.error(e, e);
348                                                    }
349                                            }
350                                    }
351    
352                                    javaClass = javaClass.getSuperclass();
353                            }
354                    }
355                    catch (Exception e) {
356                            throw new UnmarshallException(
357                                    "Unable to match field " + fieldName, e);
358                    }
359    
360                    return javaClassInstance;
361            }
362    
363            private static final Class<?>[] _JSON_CLASSES = {JSONObject.class};
364    
365            private static final Class<?>[] _SERIALIZABLE_CLASSES =
366                    {Serializable.class};
367    
368            private static Log _log = LogFactoryUtil.getLog(LiferaySerializer.class);
369    
370    }