1 /* 2 * Copyright (c) 1996, 2015, 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 package sun.tools.serialver; 27 28 import java.io.*; 29 import java.io.ObjectStreamClass; 30 import java.nio.file.Paths; 31 import java.text.MessageFormat; 32 import java.util.ResourceBundle; 33 import java.util.MissingResourceException; 34 import java.net.URLClassLoader; 35 import java.net.URL; 36 import java.net.MalformedURLException; 37 38 /** 39 * Supporting class for the serialver tool. 40 */ 41 public class SerialVer { 42 43 /* 44 * A class loader that will load from the CLASSPATH environment 45 * variable set by the user. 46 */ 47 static URLClassLoader loader = null; 48 49 /* 50 * Create a URL class loader that will load classes from the 51 * specified classpath. 52 */ 53 static void initializeLoader(String cp) throws IOException { 54 String[] paths = cp.split(File.pathSeparator); 55 int count = paths.length; 56 URL[] urls = new URL[count]; 57 for (int i = 0; i < count; i++) { 58 urls[i] = Paths.get(paths[i]).toUri().toURL(); 59 } 60 loader = new URLClassLoader(urls); 61 } 62 63 /* 64 * From the classname find the serialVersionUID string formatted 65 * for to be copied to a java class. 66 */ 67 static String serialSyntax(String classname) throws ClassNotFoundException { 68 String ret = null; 69 boolean classFound = false; 70 71 // If using old style of qualifying inner classes with '$'s. 72 if (classname.indexOf('$') != -1) { 73 ret = resolveClass(classname); 74 } else { 75 /* Try to resolve the fully qualified name and if that fails, start 76 * replacing the '.'s with '$'s starting from the last '.', until 77 * the class is resolved. 78 */ 79 try { 80 ret = resolveClass(classname); 81 classFound = true; 82 } catch (ClassNotFoundException e) { 83 /* Class not found so far */ 84 } 85 if (!classFound) { 86 StringBuilder workBuffer = new StringBuilder(classname); 87 String workName = workBuffer.toString(); 88 int i; 89 while ((i = workName.lastIndexOf('.')) != -1 && !classFound) { 90 workBuffer.setCharAt(i, '$'); 91 try { 92 workName = workBuffer.toString(); 93 ret = resolveClass(workName); 94 classFound = true; 95 } catch (ClassNotFoundException e) { 96 /* Continue searching */ 97 } 98 } 99 } 100 if (!classFound) { 101 throw new ClassNotFoundException(); 102 } 103 } 104 return ret; 105 } 106 107 static String resolveClass(String classname) throws ClassNotFoundException { 108 Class<?> cl = Class.forName(classname, false, loader); 109 ObjectStreamClass desc = ObjectStreamClass.lookup(cl); 110 if (desc != null) { 111 return " private static final long serialVersionUID = " + 112 desc.getSerialVersionUID() + "L;"; 113 } else { 114 return null; 115 } 116 } 117 118 /** 119 * Entry point for serialver tool. 120 * @param args the arguments 121 */ 122 public static void main(String[] args) { 123 String envcp = null; 124 int i = 0; 125 126 if (args.length == 0) { 127 usage(); 128 System.exit(1); 129 } 130 131 for (i = 0; i < args.length; i++) { 132 if (args[i].equals("-classpath")) { 133 if ((i+1 == args.length) || args[i+1].startsWith("-")) { 134 System.err.println(Res.getText("error.missing.classpath")); 135 usage(); 136 System.exit(1); 137 } 138 envcp = new String(args[i+1]); 139 i++; 140 } else if (args[i].startsWith("-")) { 141 System.err.println(Res.getText("invalid.flag", args[i])); 142 usage(); 143 System.exit(1); 144 } else { 145 break; // drop into processing class names 146 } 147 } 148 149 150 /* 151 * Get user's CLASSPATH environment variable, if the -classpath option 152 * is not defined, and make a loader that can read from that path. 153 */ 154 if (envcp == null) { 155 envcp = System.getProperty("env.class.path"); 156 /* 157 * If environment variable not set, add current directory to path. 158 */ 159 if (envcp == null) { 160 envcp = "."; 161 } 162 } 163 164 try { 165 initializeLoader(envcp); 166 } catch (MalformedURLException mue) { 167 System.err.println(Res.getText("error.parsing.classpath", envcp)); 168 System.exit(2); 169 } catch (IOException ioe) { 170 System.err.println(Res.getText("error.parsing.classpath", envcp)); 171 System.exit(3); 172 } 173 174 /* 175 * Check if there are any class names specified 176 */ 177 if (i == args.length) { 178 usage(); 179 System.exit(1); 180 } 181 182 /* 183 * The rest of the parameters are classnames. 184 */ 185 boolean exitFlag = false; 186 for (i = i; i < args.length; i++ ) { 187 try { 188 String syntax = serialSyntax(args[i]); 189 if (syntax != null) 190 System.out.println(args[i] + ":" + syntax); 191 else { 192 System.err.println(Res.getText("NotSerializable", 193 args[i])); 194 exitFlag = true; 195 } 196 } catch (ClassNotFoundException cnf) { 197 System.err.println(Res.getText("ClassNotFound", args[i])); 198 exitFlag = true; 199 } 200 } 201 if (exitFlag) { 202 System.exit(1); 203 } 204 } 205 206 207 /** 208 * Usage 209 */ 210 public static void usage() { 211 System.err.println(Res.getText("usage")); 212 } 213 214 } 215 216 /** 217 * Utility for integrating with serialver and for localization. 218 * Handle Resources. Access to error and warning counts. 219 * Message formatting. 220 * 221 * @see java.util.ResourceBundle 222 * @see java.text.MessageFormat 223 */ 224 class Res { 225 226 private static ResourceBundle messageRB; 227 228 /** 229 * Initialize ResourceBundle 230 */ 231 static void initResource() { 232 try { 233 messageRB = 234 ResourceBundle.getBundle("sun.tools.serialver.resources.serialver"); 235 } catch (MissingResourceException e) { 236 throw new Error("Fatal: Resource for serialver is missing"); 237 } 238 } 239 240 /** 241 * get and format message string from resource 242 * 243 * @param key selects message from resource 244 */ 245 static String getText(String key) { 246 return getText(key, (String)null); 247 } 248 249 /** 250 * get and format message string from resource 251 * 252 * @param key selects message from resource 253 * @param a1 first argument 254 */ 255 static String getText(String key, String a1) { 256 return getText(key, a1, null); 257 } 258 259 /** 260 * get and format message string from resource 261 * 262 * @param key selects message from resource 263 * @param a1 first argument 264 * @param a2 second argument 265 */ 266 static String getText(String key, String a1, String a2) { 267 return getText(key, a1, a2, null); 268 } 269 270 /** 271 * get and format message string from resource 272 * 273 * @param key selects message from resource 274 * @param a1 first argument 275 * @param a2 second argument 276 * @param a3 third argument 277 */ 278 static String getText(String key, String a1, String a2, String a3) { 279 if (messageRB == null) { 280 initResource(); 281 } 282 try { 283 String message = messageRB.getString(key); 284 return MessageFormat.format(message, a1, a2, a3); 285 } catch (MissingResourceException e) { 286 throw new Error("Fatal: Resource for serialver is broken. There is no " + key + " key in resource."); 287 } 288 } 289 }