TypeSignature.java revision 2571:10fc81ac75b4
1/*
2 * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package com.sun.tools.javah;
28
29import java.util.*;
30import javax.lang.model.element.Name;
31import javax.lang.model.element.TypeElement;
32import javax.lang.model.type.ArrayType;
33import javax.lang.model.type.DeclaredType;
34import javax.lang.model.type.NoType;
35import javax.lang.model.type.PrimitiveType;
36import javax.lang.model.type.TypeKind;
37import javax.lang.model.type.TypeMirror;
38import javax.lang.model.type.TypeVariable;
39import javax.lang.model.type.TypeVisitor;
40import javax.lang.model.util.Elements;
41import javax.lang.model.util.SimpleTypeVisitor9;
42
43/**
44 * Returns internal type signature.
45 *
46 * <p><b>This is NOT part of any supported API.
47 * If you write code that depends on this, you do so at your own
48 * risk.  This code and its internal interfaces are subject to change
49 * or deletion without notice.</b></p>
50 *
51 * @author Sucheta Dambalkar
52 */
53
54public class TypeSignature {
55    static class SignatureException extends Exception {
56        private static final long serialVersionUID = 1L;
57        SignatureException(String reason) {
58            super(reason);
59        }
60    }
61
62    Elements elems;
63
64    /* Signature Characters */
65
66    private static final String SIG_VOID                   = "V";
67    private static final String SIG_BOOLEAN                = "Z";
68    private static final String SIG_BYTE                   = "B";
69    private static final String SIG_CHAR                   = "C";
70    private static final String SIG_SHORT                  = "S";
71    private static final String SIG_INT                    = "I";
72    private static final String SIG_LONG                   = "J";
73    private static final String SIG_FLOAT                  = "F";
74    private static final String SIG_DOUBLE                 = "D";
75    private static final String SIG_ARRAY                  = "[";
76    private static final String SIG_CLASS                  = "L";
77
78
79
80    public TypeSignature(Elements elems){
81        this.elems = elems;
82    }
83
84    /*
85     * Returns the type signature of a field according to JVM specs
86     */
87    public String getTypeSignature(String javasignature) throws SignatureException {
88        return getParamJVMSignature(javasignature);
89    }
90
91    /*
92     * Returns the type signature of a method according to JVM specs
93     */
94    public String getTypeSignature(String javasignature, TypeMirror returnType)
95            throws SignatureException {
96        String signature = null; //Java type signature.
97        String typeSignature = null; //Internal type signature.
98        List<String> params = new ArrayList<>(); //List of parameters.
99        String paramsig = null; //Java parameter signature.
100        String paramJVMSig = null; //Internal parameter signature.
101        String returnSig = null; //Java return type signature.
102        String returnJVMType = null; //Internal return type signature.
103        int dimensions = 0; //Array dimension.
104
105        int startIndex = -1;
106        int endIndex = -1;
107        StringTokenizer st = null;
108        int i = 0;
109
110        // Gets the actual java signature without parentheses.
111        if (javasignature != null) {
112            startIndex = javasignature.indexOf("(");
113            endIndex = javasignature.indexOf(")");
114        }
115
116        if (((startIndex != -1) && (endIndex != -1))
117            &&(startIndex+1 < javasignature.length())
118            &&(endIndex < javasignature.length())) {
119            signature = javasignature.substring(startIndex+1, endIndex);
120        }
121
122        // Separates parameters.
123        if (signature != null) {
124            if (signature.contains(",")) {
125                st = new StringTokenizer(signature, ",");
126                if (st != null) {
127                    while (st.hasMoreTokens()) {
128                        params.add(st.nextToken());
129                    }
130                }
131            } else {
132                params.add(signature);
133            }
134        }
135
136        /* JVM type signature. */
137        typeSignature = "(";
138
139        // Gets indivisual internal parameter signature.
140        while (params.isEmpty() != true) {
141            paramsig = params.remove(i).trim();
142            paramJVMSig  = getParamJVMSignature(paramsig);
143            if (paramJVMSig != null) {
144                typeSignature += paramJVMSig;
145            }
146        }
147
148        typeSignature += ")";
149
150        // Get internal return type signature.
151
152        returnJVMType = "";
153        if (returnType != null) {
154            dimensions = dimensions(returnType);
155        }
156
157        //Gets array dimension of return type.
158        while (dimensions-- > 0) {
159            returnJVMType += "[";
160        }
161        if (returnType != null) {
162            returnSig = qualifiedTypeName(returnType);
163            returnJVMType += getComponentType(returnSig);
164        } else {
165            System.out.println("Invalid return type.");
166        }
167
168        typeSignature += returnJVMType;
169
170        return typeSignature;
171    }
172
173    /*
174     * Returns internal signature of a parameter.
175     */
176    private String getParamJVMSignature(String paramsig) throws SignatureException {
177        String paramJVMSig = "";
178        String componentType ="";
179
180        if(paramsig != null){
181
182            if(paramsig.contains("[]")) {
183                // Gets array dimension.
184                int endindex = paramsig.indexOf("[]");
185                componentType = paramsig.substring(0, endindex);
186                String dimensionString =  paramsig.substring(endindex);
187                if(dimensionString != null){
188                    while(dimensionString.contains("[]")){
189                        paramJVMSig += "[";
190                        int beginindex = dimensionString.indexOf("]") + 1;
191                        if(beginindex < dimensionString.length()){
192                            dimensionString = dimensionString.substring(beginindex);
193                        }else
194                            dimensionString = "";
195                    }
196                }
197            } else componentType = paramsig;
198
199            paramJVMSig += getComponentType(componentType);
200        }
201        return paramJVMSig;
202    }
203
204    /*
205     * Returns internal signature of a component.
206     */
207    private String getComponentType(String componentType) throws SignatureException {
208
209        String JVMSig = "";
210
211        if(componentType != null){
212            switch (componentType) {
213                case "void":    JVMSig += SIG_VOID;    break;
214                case "boolean": JVMSig += SIG_BOOLEAN; break;
215                case "byte":    JVMSig += SIG_BYTE;    break;
216                case "char":    JVMSig += SIG_CHAR;    break;
217                case "short":   JVMSig += SIG_SHORT;   break;
218                case "int":     JVMSig += SIG_INT;     break;
219                case "long":    JVMSig += SIG_LONG;    break;
220                case "float":   JVMSig += SIG_FLOAT;   break;
221                case "double":  JVMSig += SIG_DOUBLE;  break;
222                default:
223                    if (!componentType.equals("")) {
224                        TypeElement classNameDoc = elems.getTypeElement(componentType);
225
226                        if (classNameDoc == null) {
227                            throw new SignatureException(componentType);
228                        }
229                        else {
230                            String classname = classNameDoc.getQualifiedName().toString();
231                            String newclassname = classname.replace('.', '/');
232                            JVMSig += "L";
233                            JVMSig += newclassname;
234                            JVMSig += ";";
235                        }
236                    }
237                    break;
238            }
239        }
240        return JVMSig;
241    }
242
243    int dimensions(TypeMirror t) {
244        if (t.getKind() != TypeKind.ARRAY)
245            return 0;
246        return 1 + dimensions(((ArrayType) t).getComponentType());
247    }
248
249
250    String qualifiedTypeName(TypeMirror type) {
251        TypeVisitor<Name, Void> v = new SimpleTypeVisitor9<Name, Void>() {
252            @Override
253            public Name visitArray(ArrayType t, Void p) {
254                return t.getComponentType().accept(this, p);
255            }
256
257            @Override
258            public Name visitDeclared(DeclaredType t, Void p) {
259                return ((TypeElement) t.asElement()).getQualifiedName();
260            }
261
262            @Override
263            public Name visitPrimitive(PrimitiveType t, Void p) {
264                return elems.getName(t.toString());
265            }
266
267            @Override
268            public Name visitNoType(NoType t, Void p) {
269                if (t.getKind() == TypeKind.VOID)
270                    return elems.getName("void");
271                return defaultAction(t, p);
272            }
273
274            @Override
275            public Name visitTypeVariable(TypeVariable t, Void p) {
276                return t.getUpperBound().accept(this, p);
277            }
278        };
279        return v.visit(type).toString();
280    }
281}
282