| /* |
| * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| |
| package vm.share.options; |
| |
| import java.lang.reflect.Array; |
| import java.util.HashMap; |
| import java.util.Map; |
| import nsk.share.TestBug; |
| |
| /** |
| * A utility class used to parse arguments of various primitive types. |
| */ |
| public class PrimitiveParser |
| { |
| /** |
| * Checks if the parser can handle passed type ("primitive/wrapper" or one-dim array of those). |
| * Note that one-dim arrays of primitives/strings/wrappers are also supported. |
| * @param type the type to parse against |
| * @return true, if can parse. |
| */ |
| public static boolean canHandle(Class<?> type) |
| { |
| |
| if(type.isArray()) |
| { |
| Class<?> compType = type.getComponentType(); |
| if(compType.isArray()) return false; // Cannot handle multidimensional arrays |
| return canHandle(compType); |
| } |
| type = convertPrimitiveTypeToWrapper(type); |
| return parsers.containsKey(type); |
| } |
| |
| /** |
| * A simple helper method. |
| * @param type the type to check for |
| * @return the parser to use, null if there is none. |
| */ |
| private static PParser getParser(Class<?> type) |
| { |
| return parsers.get(convertPrimitiveTypeToWrapper(type)); |
| } |
| |
| /** |
| * The main API method of this class. |
| * @param param the parameter to parse |
| * @param type parameter type to parse against |
| * @return returns the object of a given type. |
| * @throws vm.share.options.PrimitiveParser.ParserException |
| */ |
| public static Object parse(String param, Class<?> type) throws ParserException |
| { |
| if(type.isArray()) |
| { |
| Class<?> compType = type.getComponentType(); |
| if(compType.isArray()) |
| throw new ParserException("Cannot handle multidimensional arrays"); |
| |
| if(!canHandle(compType)) |
| throw new ParserException("Unable to parse unknown array component type " + compType); |
| |
| String[] params = param.split(","); |
| Object arr = Array.newInstance(compType, params.length); |
| for (int i = 0; i < params.length; i++) |
| { |
| String par = params[i].trim(); |
| Array.set(arr, i, parse(par, compType)); |
| } |
| return arr; |
| } |
| else |
| { |
| if(!canHandle(type)) |
| throw new ParserException("Unable to parse unknown type " + type); |
| return getParser(type).parse(param); |
| } |
| } |
| |
| // I'm not sure, if generics are of any use here... |
| static private abstract class PParser<T> |
| { |
| abstract T parse(String param) throws ParserException; |
| |
| // Class<T> getClassKey() |
| // { |
| // return PrimitiveParser.(Class<T>) T.getClass(); |
| // } |
| } |
| |
| /** |
| * Converts primitive types to corresponding wrapper classes. |
| * We could register int.class, boolean.class etc in the hashtable instead. |
| * (Or Integer.TYPE, etc.) |
| * @param type to convert to wrapper |
| * @return wrapper class or type if it is not primitive |
| */ |
| public static Class<?> convertPrimitiveTypeToWrapper(Class<?> type) |
| { |
| if(!type.isPrimitive()) return type; |
| Object arr = Array.newInstance(type, 1); |
| Object v = Array.get(arr, 0); |
| return v.getClass(); |
| } |
| |
| |
| //"kind of state" machine stuff |
| |
| private static Map<Class<?>, PParser<?>> parsers; |
| |
| static |
| { |
| parsers = new HashMap<Class<?>, PrimitiveParser.PParser<?>>(16); |
| parsers.put(Integer.class, new PParser<Integer>() |
| { |
| @Override Integer parse(String param) throws ParserException |
| { |
| if ( param.startsWith("0x") ) |
| return Integer.parseInt(param.substring(2)); |
| else |
| return Integer.valueOf(param); |
| } |
| }); |
| parsers.put(Boolean.class, new PParser<Boolean>() |
| { |
| @Override Boolean parse(String param) throws ParserException |
| { |
| //special behavior for options |
| if(param == null) return true; |
| if(param.trim().length()==0) return true; |
| return Boolean.valueOf(param); |
| } |
| }); |
| |
| parsers.put(String.class, new PParser<String>() |
| { |
| @Override String parse(String param) throws ParserException |
| { |
| if(param == null) throw new ParserException(" Got null value string."); |
| return param; |
| } |
| }); |
| |
| |
| parsers.put(Character.class, new PParser<Character>() |
| { |
| @Override Character parse(String param) throws ParserException |
| { |
| if(param.length()!=1) |
| throw new TestBug("Found Character type option of length != 1"); |
| return Character.valueOf(param.charAt(0)); |
| } |
| }); |
| |
| parsers.put(Byte.class, new PParser<Byte>() |
| { |
| @Override Byte parse(String param) throws ParserException |
| { |
| if ( param.startsWith("0x") ) |
| return Byte.parseByte(param.substring(2)); |
| else |
| return Byte.valueOf(param); |
| } |
| }); |
| |
| parsers.put(Short.class, new PParser<Short>() |
| { |
| @Override Short parse(String param) throws ParserException |
| { |
| if ( param.startsWith("0x") ) |
| return Short.parseShort(param.substring(2)); |
| else |
| return Short.valueOf(param); |
| } |
| }); |
| |
| parsers.put(Long.class, new PParser<Long>() |
| { |
| @Override Long parse(String param) throws ParserException |
| { |
| if ( param.startsWith("0x") ) |
| return Long.parseLong(param.substring(2)); |
| else |
| return Long.valueOf(param); |
| } |
| }); |
| |
| parsers.put(Float.class, new PParser<Float>() |
| { |
| @Override Float parse(String param) throws ParserException |
| { |
| return Float.valueOf(param); |
| } |
| }); |
| |
| parsers.put(Double.class, new PParser<Double>() |
| { |
| @Override Double parse(String param) throws ParserException |
| { |
| return Double.valueOf(param); |
| } |
| }); |
| } |
| |
| |
| /* Discussion |
| * 1. It was proposed to use instead of the convertPrimitive the following |
| * |
| * private static Map<Class<?>, Class<?>> wrapperClasses = new HashMap<Class<?>, Class<?>>(); |
| * |
| * so we could do if(type.isPrimitive()) |
| type = wrapperClasses.get(type); |
| static { |
| wrapperClasses.put(boolean.class, Boolean.class); |
| wrapperClasses.put(short.class, Short.class); |
| wrapperClasses.put(int.class, Integer.class); |
| wrapperClasses.put(Long.Type, Long.class); // we can do it this way! |
| wrapperClasses.put(float.class, Float.class); |
| wrapperClasses.put(double.class, Double.class); |
| } |
| * The alternative is to register PParsers with corresponding Primitive type too. |
| * |
| * Also canHandle() could use |
| return wrapperClasses.keySet().contains(type) || wrapperClasses.entrySet().contains(type); |
| |
| * 2. Parsing can be implemented via reflection |
| return type.getMethod("valueOf", new Class[]{String.class}).invoke(null, string); |
| |
| * I don't like using reflection as it prevents optimisation, |
| * also now Strings and Characters are handled in a nice fashion. |
| * |
| * As for convertToPrimitive trick both ways are good, |
| * but current looks more generic though tricky |
| */ |
| |
| //// some test, should it be commented out? |
| // public static void main(String[] args) |
| // { |
| // try |
| // { |
| // String str = "0"; |
| // Object o = null; |
| // str = "0"; |
| // o = parse(str, String.class); |
| // System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); |
| // |
| // str = "0"; |
| // o = parse(str, int.class); |
| // System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); |
| // str = "0"; |
| // o = parse(str, Integer.class); |
| // System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); |
| // |
| // str = "0,1,2"; |
| // o = parse(str, int[].class); |
| // System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + (int[]) o + "#"); |
| // System.out.println("DATA:" + java.util.Arrays.toString((int[])o)); |
| // // System.out.println("DATA:" + java.util.Arrays.deepToString( (int[]) o)); |
| // |
| // str = "0"; |
| // o = parse(str, byte.class); |
| // System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); |
| // |
| // str = "0"; |
| // o = parse(str, HashMap.class); |
| // System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); |
| //// String str = "0"; Object o = parsePrimitiveString(help_option, type); System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); |
| // } catch (ParserException ex) |
| // { |
| // System.out.println("" +ex); |
| // } |
| //// String str = "0"; Object o = parsePrimitiveString(help_option, type); System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); |
| // |
| // } |
| |
| } |