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;
016    
017    import com.liferay.portal.kernel.json.JSON;
018    
019    import java.lang.reflect.Field;
020    import java.lang.reflect.Method;
021    
022    import java.util.ArrayList;
023    import java.util.HashMap;
024    import java.util.List;
025    import java.util.Map;
026    
027    /**
028     * @author Igor Spasic
029     */
030    public class JSONIncludesManager {
031    
032            public String[] lookupExcludes(Class<?> type) {
033                    String[] excludes = _excludesMap.get(type);
034    
035                    if (excludes != null) {
036                            return excludes;
037                    }
038    
039                    List<String> list = new ArrayList<String>();
040    
041                    while (type != null) {
042                            JSON jsonAnnotation = type.getAnnotation(JSON.class);
043    
044                            if ((jsonAnnotation != null) && jsonAnnotation.strict()) {
045                                    list.add(_EXCLUDE_ALL);
046    
047                                    break;
048                            }
049                            else {
050                                    _scanFieldsAndMethods(list, type, false);
051                            }
052    
053                            type = type.getSuperclass();
054                    }
055    
056                    excludes = _listToArray(list);
057    
058                    _excludesMap.put(type, excludes);
059    
060                    return excludes;
061            }
062    
063            public String[] lookupIncludes(Class<?> type) {
064                    String[] includes = _includesMap.get(type);
065    
066                    if (includes != null) {
067                            return includes;
068                    }
069    
070                    List<String> list = new ArrayList<String>();
071    
072                    while (type != null) {
073                            _scanFieldsAndMethods(list, type, true);
074    
075                            type = type.getSuperclass();
076                    }
077    
078                    includes = _listToArray(list);
079    
080                    _includesMap.put(type, includes);
081    
082                    return includes;
083            }
084    
085            private String _getPropertyName(Method method) {
086                    Class<?>[] parameterTypes = method.getParameterTypes();
087    
088                    if (parameterTypes.length != 0) {
089                            return null;
090                    }
091    
092                    String propertyName = null;
093    
094                    String methodName = method.getName();
095    
096                    if (methodName.startsWith("get")) {
097                            propertyName = methodName.substring(3);
098                    }
099                    else if (methodName.startsWith("is")) {
100                            propertyName = methodName.substring(2);
101                    }
102                    else {
103                            return null;
104                    }
105    
106                    if ((propertyName.length() > 2) &&
107                            Character.isUpperCase(propertyName.charAt(1))) {
108    
109                            return propertyName;
110                    }
111    
112                    return Character.toLowerCase(propertyName.charAt(0)) +
113                            propertyName.substring(1);
114            }
115    
116            private String[] _listToArray(List<String> list) {
117                    if (list.isEmpty()) {
118                            return _EMPTY_LIST;
119                    }
120                    else {
121                            return list.toArray(new String[list.size()]);
122                    }
123            }
124    
125            private void _scanFieldsAndMethods(
126                    List<String> list, Class<?> type, boolean include) {
127    
128                    Field[] fields = type.getDeclaredFields();
129    
130                    for (Field field : fields) {
131                            JSON jsonAnnotation = field.getAnnotation(JSON.class);
132    
133                            if ((jsonAnnotation != null) &&
134                                    (jsonAnnotation.include() == include)) {
135    
136                                    String name = field.getName();
137    
138                                    if (!list.contains(name)) {
139                                            list.add(name);
140                                    }
141                            }
142                    }
143    
144                    Method[] methods = type.getDeclaredMethods();
145    
146                    for (Method method : methods) {
147                            JSON jsonAnnotation = method.getAnnotation(JSON.class);
148    
149                            if ((jsonAnnotation != null) &&
150                                    (jsonAnnotation.include() == include)) {
151    
152                                    String name = _getPropertyName(method);
153    
154                                    if (name != null) {
155                                            if (!list.contains(name)) {
156                                                    list.add(name);
157                                            }
158                                    }
159                            }
160                    }
161            }
162    
163            private static final String[] _EMPTY_LIST = new String[0];
164    
165            private static final String _EXCLUDE_ALL = "*";
166    
167            private Map<Class<?>, String[]> _excludesMap =
168                    new HashMap<Class<?>, String[]>();
169            private Map<Class<?>, String[]> _includesMap =
170                    new HashMap<Class<?>, String[]>();
171    
172    }