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