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