001    /**
002     * Copyright (c) 2000-2012 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("has")) {
100                            propertyName = methodName.substring(3);
101                    }
102                    else if (methodName.startsWith("is")) {
103                            propertyName = methodName.substring(2);
104                    }
105                    else {
106                            return null;
107                    }
108    
109                    if ((propertyName.length() > 2) &&
110                            Character.isUpperCase(propertyName.charAt(1))) {
111    
112                            return propertyName;
113                    }
114    
115                    return Character.toLowerCase(propertyName.charAt(0)) +
116                            propertyName.substring(1);
117            }
118    
119            private String[] _listToArray(List<String> list) {
120                    if (list.isEmpty()) {
121                            return _EMPTY_LIST;
122                    }
123                    else {
124                            return list.toArray(new String[list.size()]);
125                    }
126            }
127    
128            private void _scanFieldsAndMethods(
129                    List<String> list, Class<?> type, boolean include) {
130    
131                    Field[] fields = type.getDeclaredFields();
132    
133                    for (Field field : fields) {
134                            JSON jsonAnnotation = field.getAnnotation(JSON.class);
135    
136                            if ((jsonAnnotation != null) &&
137                                    (jsonAnnotation.include() == include)) {
138    
139                                    String name = field.getName();
140    
141                                    if (!list.contains(name)) {
142                                            list.add(name);
143                                    }
144                            }
145                    }
146    
147                    Method[] methods = type.getDeclaredMethods();
148    
149                    for (Method method : methods) {
150                            JSON jsonAnnotation = method.getAnnotation(JSON.class);
151    
152                            if ((jsonAnnotation != null) &&
153                                    (jsonAnnotation.include() == include)) {
154    
155                                    String name = _getPropertyName(method);
156    
157                                    if (name != null) {
158                                            if (!list.contains(name)) {
159                                                    list.add(name);
160                                            }
161                                    }
162                            }
163                    }
164            }
165    
166            private static final String[] _EMPTY_LIST = new String[0];
167    
168            private static final String _EXCLUDE_ALL = "*";
169    
170            private Map<Class<?>, String[]> _excludesMap =
171                    new HashMap<Class<?>, String[]>();
172            private Map<Class<?>, String[]> _includesMap =
173                    new HashMap<Class<?>, String[]>();
174    
175    }