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