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