Thu, 31 Aug 2017 15:18:52 +0800
merge
aoqi@0 | 1 | /* |
aoqi@0 | 2 | * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. |
aoqi@0 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@0 | 4 | * |
aoqi@0 | 5 | * This code is free software; you can redistribute it and/or modify it |
aoqi@0 | 6 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@0 | 7 | * published by the Free Software Foundation. Oracle designates this |
aoqi@0 | 8 | * particular file as subject to the "Classpath" exception as provided |
aoqi@0 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
aoqi@0 | 10 | * |
aoqi@0 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@0 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@0 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@0 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@0 | 15 | * accompanied this code). |
aoqi@0 | 16 | * |
aoqi@0 | 17 | * You should have received a copy of the GNU General Public License version |
aoqi@0 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@0 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@0 | 20 | * |
aoqi@0 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@0 | 22 | * or visit www.oracle.com if you need additional information or have any |
aoqi@0 | 23 | * questions. |
aoqi@0 | 24 | */ |
aoqi@0 | 25 | |
aoqi@0 | 26 | package com.sun.xml.internal.bind.api.impl; |
aoqi@0 | 27 | |
aoqi@0 | 28 | import javax.lang.model.SourceVersion; |
aoqi@0 | 29 | import java.util.ArrayList; |
aoqi@0 | 30 | import java.util.List; |
aoqi@0 | 31 | import java.util.StringTokenizer; |
aoqi@0 | 32 | |
aoqi@0 | 33 | /** |
aoqi@0 | 34 | * Converts aribitrary strings into Java identifiers. |
aoqi@0 | 35 | * |
aoqi@0 | 36 | * @author |
aoqi@0 | 37 | * <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> |
aoqi@0 | 38 | */ |
aoqi@0 | 39 | public interface NameConverter |
aoqi@0 | 40 | { |
aoqi@0 | 41 | /** |
aoqi@0 | 42 | * converts a string into an identifier suitable for classes. |
aoqi@0 | 43 | * |
aoqi@0 | 44 | * In general, this operation should generate "NamesLikeThis". |
aoqi@0 | 45 | */ |
aoqi@0 | 46 | String toClassName( String token ); |
aoqi@0 | 47 | |
aoqi@0 | 48 | /** |
aoqi@0 | 49 | * converts a string into an identifier suitable for interfaces. |
aoqi@0 | 50 | * |
aoqi@0 | 51 | * In general, this operation should generate "NamesLikeThis". |
aoqi@0 | 52 | * But for example, it can prepend every interface with 'I'. |
aoqi@0 | 53 | */ |
aoqi@0 | 54 | String toInterfaceName( String token ); |
aoqi@0 | 55 | |
aoqi@0 | 56 | /** |
aoqi@0 | 57 | * converts a string into an identifier suitable for properties. |
aoqi@0 | 58 | * |
aoqi@0 | 59 | * In general, this operation should generate "NamesLikeThis", |
aoqi@0 | 60 | * which will be used with known prefixes like "get" or "set". |
aoqi@0 | 61 | */ |
aoqi@0 | 62 | String toPropertyName( String token ); |
aoqi@0 | 63 | |
aoqi@0 | 64 | /** |
aoqi@0 | 65 | * converts a string into an identifier suitable for constants. |
aoqi@0 | 66 | * |
aoqi@0 | 67 | * In the standard Java naming convention, this operation should |
aoqi@0 | 68 | * generate "NAMES_LIKE_THIS". |
aoqi@0 | 69 | */ |
aoqi@0 | 70 | String toConstantName( String token ); |
aoqi@0 | 71 | |
aoqi@0 | 72 | /** |
aoqi@0 | 73 | * Converts a string into an identifier suitable for variables. |
aoqi@0 | 74 | * |
aoqi@0 | 75 | * In general it should generate "namesLikeThis". |
aoqi@0 | 76 | */ |
aoqi@0 | 77 | String toVariableName( String token ); |
aoqi@0 | 78 | |
aoqi@0 | 79 | /** |
aoqi@0 | 80 | * Converts a namespace URI into a package name. |
aoqi@0 | 81 | * This method should expect strings like |
aoqi@0 | 82 | * "http://foo.bar.zot/org", "urn:abc:def:ghi" "", or even "###" |
aoqi@0 | 83 | * (basically anything) and expected to return a package name, |
aoqi@0 | 84 | * liks "org.acme.foo". |
aoqi@0 | 85 | * |
aoqi@0 | 86 | */ |
aoqi@0 | 87 | String toPackageName( String namespaceUri ); |
aoqi@0 | 88 | |
aoqi@0 | 89 | /** |
aoqi@0 | 90 | * The name converter implemented by Code Model. |
aoqi@0 | 91 | * |
aoqi@0 | 92 | * This is the standard name conversion for JAXB. |
aoqi@0 | 93 | */ |
aoqi@0 | 94 | public static final NameConverter standard = new Standard(); |
aoqi@0 | 95 | |
aoqi@0 | 96 | static class Standard extends NameUtil implements NameConverter { |
aoqi@0 | 97 | public String toClassName(String s) { |
aoqi@0 | 98 | return toMixedCaseName(toWordList(s), true); |
aoqi@0 | 99 | } |
aoqi@0 | 100 | public String toVariableName(String s) { |
aoqi@0 | 101 | return toMixedCaseName(toWordList(s), false); |
aoqi@0 | 102 | } |
aoqi@0 | 103 | public String toInterfaceName( String token ) { |
aoqi@0 | 104 | return toClassName(token); |
aoqi@0 | 105 | } |
aoqi@0 | 106 | public String toPropertyName(String s) { |
aoqi@0 | 107 | String prop = toClassName(s); |
aoqi@0 | 108 | // property name "Class" with collide with Object.getClass, |
aoqi@0 | 109 | // so escape this. |
aoqi@0 | 110 | if(prop.equals("Class")) |
aoqi@0 | 111 | prop = "Clazz"; |
aoqi@0 | 112 | return prop; |
aoqi@0 | 113 | } |
aoqi@0 | 114 | public String toConstantName( String token ) { |
aoqi@0 | 115 | return super.toConstantName(token); |
aoqi@0 | 116 | } |
aoqi@0 | 117 | /** |
aoqi@0 | 118 | * Computes a Java package name from a namespace URI, |
aoqi@0 | 119 | * as specified in the spec. |
aoqi@0 | 120 | * |
aoqi@0 | 121 | * @return |
aoqi@0 | 122 | * null if it fails to derive a package name. |
aoqi@0 | 123 | */ |
aoqi@0 | 124 | public String toPackageName( String nsUri ) { |
aoqi@0 | 125 | // remove scheme and :, if present |
aoqi@0 | 126 | // spec only requires us to remove 'http' and 'urn'... |
aoqi@0 | 127 | int idx = nsUri.indexOf(':'); |
aoqi@0 | 128 | String scheme = ""; |
aoqi@0 | 129 | if(idx>=0) { |
aoqi@0 | 130 | scheme = nsUri.substring(0,idx); |
aoqi@0 | 131 | if( scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("urn") ) |
aoqi@0 | 132 | nsUri = nsUri.substring(idx+1); |
aoqi@0 | 133 | } |
aoqi@0 | 134 | |
aoqi@0 | 135 | // tokenize string |
aoqi@0 | 136 | ArrayList<String> tokens = tokenize( nsUri, "/: " ); |
aoqi@0 | 137 | if( tokens.size() == 0 ) { |
aoqi@0 | 138 | return null; |
aoqi@0 | 139 | } |
aoqi@0 | 140 | |
aoqi@0 | 141 | // remove trailing file type, if necessary |
aoqi@0 | 142 | if( tokens.size() > 1 ) { |
aoqi@0 | 143 | // for uri's like "www.foo.com" and "foo.com", there is no trailing |
aoqi@0 | 144 | // file, so there's no need to look at the last '.' and substring |
aoqi@0 | 145 | // otherwise, we loose the "com" (which would be wrong) |
aoqi@0 | 146 | String lastToken = tokens.get( tokens.size()-1 ); |
aoqi@0 | 147 | idx = lastToken.lastIndexOf( '.' ); |
aoqi@0 | 148 | if( idx > 0 ) { |
aoqi@0 | 149 | lastToken = lastToken.substring( 0, idx ); |
aoqi@0 | 150 | tokens.set( tokens.size()-1, lastToken ); |
aoqi@0 | 151 | } |
aoqi@0 | 152 | } |
aoqi@0 | 153 | |
aoqi@0 | 154 | // tokenize domain name and reverse. Also remove :port if it exists |
aoqi@0 | 155 | String domain = tokens.get( 0 ); |
aoqi@0 | 156 | idx = domain.indexOf(':'); |
aoqi@0 | 157 | if( idx >= 0) domain = domain.substring(0, idx); |
aoqi@0 | 158 | ArrayList<String> r = reverse( tokenize( domain, scheme.equals("urn")?".-":"." ) ); |
aoqi@0 | 159 | if( r.get( r.size()-1 ).equalsIgnoreCase( "www" ) ) { |
aoqi@0 | 160 | // remove leading www |
aoqi@0 | 161 | r.remove( r.size()-1 ); |
aoqi@0 | 162 | } |
aoqi@0 | 163 | |
aoqi@0 | 164 | // replace the domain name with tokenized items |
aoqi@0 | 165 | tokens.addAll( 1, r ); |
aoqi@0 | 166 | tokens.remove( 0 ); |
aoqi@0 | 167 | |
aoqi@0 | 168 | // iterate through the tokens and apply xml->java name algorithm |
aoqi@0 | 169 | for( int i = 0; i < tokens.size(); i++ ) { |
aoqi@0 | 170 | |
aoqi@0 | 171 | // get the token and remove illegal chars |
aoqi@0 | 172 | String token = tokens.get( i ); |
aoqi@0 | 173 | token = removeIllegalIdentifierChars( token ); |
aoqi@0 | 174 | |
aoqi@0 | 175 | // this will check for reserved keywords |
aoqi@0 | 176 | if (SourceVersion.isKeyword(token.toLowerCase())) { |
aoqi@0 | 177 | token = '_' + token; |
aoqi@0 | 178 | } |
aoqi@0 | 179 | |
aoqi@0 | 180 | tokens.set( i, token.toLowerCase() ); |
aoqi@0 | 181 | } |
aoqi@0 | 182 | |
aoqi@0 | 183 | // concat all the pieces and return it |
aoqi@0 | 184 | return combine( tokens, '.' ); |
aoqi@0 | 185 | } |
aoqi@0 | 186 | |
aoqi@0 | 187 | |
aoqi@0 | 188 | private static String removeIllegalIdentifierChars(String token) { |
aoqi@0 | 189 | StringBuilder newToken = new StringBuilder(token.length() + 1); // max expected length |
aoqi@0 | 190 | for( int i = 0; i < token.length(); i++ ) { |
aoqi@0 | 191 | char c = token.charAt( i ); |
aoqi@0 | 192 | if (i == 0 && !Character.isJavaIdentifierStart(c)) { // c can't be used as FIRST char |
aoqi@0 | 193 | newToken.append('_'); |
aoqi@0 | 194 | } |
aoqi@0 | 195 | if (!Character.isJavaIdentifierPart(c)) { // c can't be used |
aoqi@0 | 196 | newToken.append('_'); |
aoqi@0 | 197 | } else { |
aoqi@0 | 198 | newToken.append(c); // c is valid |
aoqi@0 | 199 | } |
aoqi@0 | 200 | } |
aoqi@0 | 201 | return newToken.toString(); |
aoqi@0 | 202 | } |
aoqi@0 | 203 | |
aoqi@0 | 204 | |
aoqi@0 | 205 | private static ArrayList<String> tokenize( String str, String sep ) { |
aoqi@0 | 206 | StringTokenizer tokens = new StringTokenizer(str,sep); |
aoqi@0 | 207 | ArrayList<String> r = new ArrayList<String>(); |
aoqi@0 | 208 | |
aoqi@0 | 209 | while(tokens.hasMoreTokens()) |
aoqi@0 | 210 | r.add( tokens.nextToken() ); |
aoqi@0 | 211 | |
aoqi@0 | 212 | return r; |
aoqi@0 | 213 | } |
aoqi@0 | 214 | |
aoqi@0 | 215 | private static <T> ArrayList<T> reverse( List<T> a ) { |
aoqi@0 | 216 | ArrayList<T> r = new ArrayList<T>(); |
aoqi@0 | 217 | |
aoqi@0 | 218 | for( int i=a.size()-1; i>=0; i-- ) |
aoqi@0 | 219 | r.add( a.get(i) ); |
aoqi@0 | 220 | |
aoqi@0 | 221 | return r; |
aoqi@0 | 222 | } |
aoqi@0 | 223 | |
aoqi@0 | 224 | private static String combine( List r, char sep ) { |
aoqi@0 | 225 | StringBuilder buf = new StringBuilder(r.get(0).toString()); |
aoqi@0 | 226 | |
aoqi@0 | 227 | for( int i=1; i<r.size(); i++ ) { |
aoqi@0 | 228 | buf.append(sep); |
aoqi@0 | 229 | buf.append(r.get(i)); |
aoqi@0 | 230 | } |
aoqi@0 | 231 | |
aoqi@0 | 232 | return buf.toString(); |
aoqi@0 | 233 | } |
aoqi@0 | 234 | } |
aoqi@0 | 235 | |
aoqi@0 | 236 | /** |
aoqi@0 | 237 | * JAX-PRC compatible name converter implementation. |
aoqi@0 | 238 | * |
aoqi@0 | 239 | * The only difference is that we treat '_' as a valid character |
aoqi@0 | 240 | * and not as a word separator. |
aoqi@0 | 241 | */ |
aoqi@0 | 242 | public static final NameConverter jaxrpcCompatible = new Standard() { |
aoqi@0 | 243 | protected boolean isPunct(char c) { |
aoqi@0 | 244 | return (c == '.' || c == '-' || c == ';' /*|| c == '_'*/ || c == '\u00b7' |
aoqi@0 | 245 | || c == '\u0387' || c == '\u06dd' || c == '\u06de'); |
aoqi@0 | 246 | } |
aoqi@0 | 247 | protected boolean isLetter(char c) { |
aoqi@0 | 248 | return super.isLetter(c) || c=='_'; |
aoqi@0 | 249 | } |
aoqi@0 | 250 | |
aoqi@0 | 251 | protected int classify(char c0) { |
aoqi@0 | 252 | if(c0=='_') return NameUtil.OTHER_LETTER; |
aoqi@0 | 253 | return super.classify(c0); |
aoqi@0 | 254 | } |
aoqi@0 | 255 | }; |
aoqi@0 | 256 | |
aoqi@0 | 257 | /** |
aoqi@0 | 258 | * Smarter converter used for RELAX NG support. |
aoqi@0 | 259 | */ |
aoqi@0 | 260 | public static final NameConverter smart = new Standard() { |
aoqi@0 | 261 | public String toConstantName( String token ) { |
aoqi@0 | 262 | String name = super.toConstantName(token); |
aoqi@0 | 263 | if(!SourceVersion.isKeyword(name)) |
aoqi@0 | 264 | return name; |
aoqi@0 | 265 | else |
aoqi@0 | 266 | return '_'+name; |
aoqi@0 | 267 | } |
aoqi@0 | 268 | }; |
aoqi@0 | 269 | } |