001    /**
002     * Copyright (c) 2000-present 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.kernel.util;
016    
017    import java.util.ArrayList;
018    import java.util.List;
019    
020    /**
021     * @author Igor Spasic
022     */
023    public class MethodParameter {
024    
025            public MethodParameter(
026                    String name, String signatures, Class<?> type, boolean initialize) {
027    
028                    _name = name;
029                    _signatures = signatures;
030                    _type = type;
031    
032                    if (initialize) {
033                            try {
034                                    getGenericTypes();
035                            }
036                            catch (ClassNotFoundException cnfe) {
037                                    throw new IllegalArgumentException(cnfe);
038                            }
039                    }
040            }
041    
042            public Class<?>[] getGenericTypes() throws ClassNotFoundException {
043                    if (_initialized) {
044                            return _genericTypes;
045                    }
046    
047                    _genericTypes = _getGenericTypes(_signatures);
048    
049                    _initialized = true;
050    
051                    return _genericTypes;
052            }
053    
054            public String getName() {
055                    return _name;
056            }
057    
058            public String getSignature() {
059                    return _signatures;
060            }
061    
062            public Class<?> getType() {
063                    return _type;
064            }
065    
066            private String _getClassName(String signature) {
067                    String className = signature;
068    
069                    char c = signature.charAt(0);
070    
071                    if (_isPrimitive(c)) {
072                            if (signature.length() != 1) {
073                                    throw new IllegalArgumentException(
074                                            "Invalid signature " + signature);
075                            }
076                    }
077                    else if (c == 'L') {
078                            className = className.substring(1, className.length() - 1);
079                            className = className.replace(CharPool.SLASH, CharPool.PERIOD);
080                    }
081                    else if (c == '[') {
082                            className = className.replace(CharPool.SLASH, CharPool.PERIOD);
083                    }
084                    else {
085                            throw new IllegalArgumentException(
086                                    "Invalid signature " + signature);
087                    }
088    
089                    return className;
090            }
091    
092            private ClassLoader _getContextClassLoader() {
093                    if (_contextClassLoader != null) {
094                            return _contextClassLoader;
095                    }
096    
097                    Thread currentThread = Thread.currentThread();
098    
099                    _contextClassLoader = currentThread.getContextClassLoader();
100    
101                    return _contextClassLoader;
102            }
103    
104            private String _getGenericName(String typeName) {
105                    if (typeName.equals(StringPool.STAR)) {
106                            return null;
107                    }
108    
109                    if (typeName.startsWith(StringPool.MINUS) ||
110                            typeName.startsWith(StringPool.PLUS)) {
111    
112                            typeName = typeName.substring(1);
113                    }
114    
115                    return typeName;
116            }
117    
118            private Class<?> _getGenericType(String signature)
119                    throws ClassNotFoundException {
120    
121                    ClassLoader contextClassLoader = _getContextClassLoader();
122    
123                    String className = _getClassName(signature);
124    
125                    if (className.startsWith(StringPool.OPEN_BRACKET)) {
126                            try {
127                                    return Class.forName(className, true, contextClassLoader);
128                            }
129                            catch (ClassNotFoundException cnfe) {
130                            }
131                    }
132    
133                    return contextClassLoader.loadClass(className);
134            }
135    
136            private Class<?>[] _getGenericTypes(String signatures)
137                    throws ClassNotFoundException {
138    
139                    if (signatures == null) {
140                            return null;
141                    }
142    
143                    int leftBracketIndex = signatures.indexOf(CharPool.LESS_THAN);
144    
145                    if (leftBracketIndex == -1) {
146                            return null;
147                    }
148    
149                    int rightBracketIndex = signatures.lastIndexOf(CharPool.GREATER_THAN);
150    
151                    if (rightBracketIndex == -1) {
152                            return null;
153                    }
154    
155                    String generics = signatures.substring(
156                            leftBracketIndex + 1, rightBracketIndex);
157    
158                    List<Class<?>> genericTypeslist = new ArrayList<>();
159    
160                    int level = 0;
161                    int index = 0;
162    
163                    while (index < generics.length()) {
164                            char c = generics.charAt(index);
165    
166                            index++;
167    
168                            if (c == CharPool.LESS_THAN) {
169                                    level++;
170                            }
171                            else if (c == CharPool.GREATER_THAN) {
172                                    level--;
173                            }
174                            else if (level == 0) {
175                                    String extractedTopLevelGenericName = null;
176    
177                                    if (c == 'L') {
178                                            int bracketIndex = generics.indexOf(
179                                                    StringPool.LESS_THAN, index);
180                                            int endIndex =
181                                                    generics.indexOf(StringPool.SEMICOLON, index) + 1;
182    
183                                            if ((bracketIndex != -1) && (bracketIndex < endIndex)) {
184                                                    endIndex = bracketIndex;
185    
186                                                    extractedTopLevelGenericName = _getGenericName(
187                                                            generics.substring(index - 1, endIndex));
188                                                    extractedTopLevelGenericName =
189                                                            extractedTopLevelGenericName.concat(
190                                                                    StringPool.SEMICOLON);
191                                            }
192                                            else {
193                                                    extractedTopLevelGenericName = _getGenericName(
194                                                            generics.substring(index - 1, endIndex));
195                                            }
196    
197                                            index = endIndex;
198                                    }
199                                    else if (c == '[') {
200                                            char nextChar = generics.charAt(index);
201    
202                                            if (_isPrimitive(nextChar)) {
203                                                    extractedTopLevelGenericName = _getGenericName(
204                                                            generics.substring(index - 1, index + 1));
205    
206                                                    index++;
207                                            }
208                                            else if (nextChar == 'L') {
209                                                    int endIndex =
210                                                            generics.indexOf(StringPool.SEMICOLON, index) + 1;
211    
212                                                    extractedTopLevelGenericName = _getGenericName(
213                                                            generics.substring(index - 1, endIndex));
214    
215                                                    index = endIndex;
216                                            }
217                                    }
218    
219                                    if (Validator.isNotNull(extractedTopLevelGenericName)) {
220                                            genericTypeslist.add(
221                                                    _getGenericType(extractedTopLevelGenericName));
222                                    }
223                            }
224                    }
225    
226                    if (genericTypeslist.isEmpty()) {
227                            return null;
228                    }
229    
230                    return genericTypeslist.toArray(new Class<?>[genericTypeslist.size()]);
231            }
232    
233            private boolean _isPrimitive(char c) {
234                    if ((c == 'B') || (c == 'C') || (c == 'D') || (c == 'F') ||
235                            (c == 'I') || (c == 'J') || (c == 'S') || (c == 'V') ||
236                            (c == 'Z')) {
237    
238                            return true;
239                    }
240                    else {
241                            return false;
242                    }
243            }
244    
245            private ClassLoader _contextClassLoader;
246            private Class<?>[] _genericTypes;
247            private boolean _initialized;
248            private final String _name;
249            private final String _signatures;
250            private final Class<?> _type;
251    
252    }