Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/share/options/PrimitiveParser.java
41155 views
/*1* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/222324package vm.share.options;2526import java.lang.reflect.Array;27import java.util.HashMap;28import java.util.Map;29import nsk.share.TestBug;3031/**32* A utility class used to parse arguments of various primitive types.33*/34public class PrimitiveParser35{36/**37* Checks if the parser can handle passed type ("primitive/wrapper" or one-dim array of those).38* Note that one-dim arrays of primitives/strings/wrappers are also supported.39* @param type the type to parse against40* @return true, if can parse.41*/42public static boolean canHandle(Class<?> type)43{4445if(type.isArray())46{47Class<?> compType = type.getComponentType();48if(compType.isArray()) return false; // Cannot handle multidimensional arrays49return canHandle(compType);50}51type = convertPrimitiveTypeToWrapper(type);52return parsers.containsKey(type);53}5455/**56* A simple helper method.57* @param type the type to check for58* @return the parser to use, null if there is none.59*/60private static PParser getParser(Class<?> type)61{62return parsers.get(convertPrimitiveTypeToWrapper(type));63}6465/**66* The main API method of this class.67* @param param the parameter to parse68* @param type parameter type to parse against69* @return returns the object of a given type.70* @throws vm.share.options.PrimitiveParser.ParserException71*/72public static Object parse(String param, Class<?> type) throws ParserException73{74if(type.isArray())75{76Class<?> compType = type.getComponentType();77if(compType.isArray())78throw new ParserException("Cannot handle multidimensional arrays");7980if(!canHandle(compType))81throw new ParserException("Unable to parse unknown array component type " + compType);8283String[] params = param.split(",");84Object arr = Array.newInstance(compType, params.length);85for (int i = 0; i < params.length; i++)86{87String par = params[i].trim();88Array.set(arr, i, parse(par, compType));89}90return arr;91}92else93{94if(!canHandle(type))95throw new ParserException("Unable to parse unknown type " + type);96return getParser(type).parse(param);97}98}99100// I'm not sure, if generics are of any use here...101static private abstract class PParser<T>102{103abstract T parse(String param) throws ParserException;104105// Class<T> getClassKey()106// {107// return PrimitiveParser.(Class<T>) T.getClass();108// }109}110111/**112* Converts primitive types to corresponding wrapper classes.113* We could register int.class, boolean.class etc in the hashtable instead.114* (Or Integer.TYPE, etc.)115* @param type to convert to wrapper116* @return wrapper class or type if it is not primitive117*/118public static Class<?> convertPrimitiveTypeToWrapper(Class<?> type)119{120if(!type.isPrimitive()) return type;121Object arr = Array.newInstance(type, 1);122Object v = Array.get(arr, 0);123return v.getClass();124}125126127//"kind of state" machine stuff128129private static Map<Class<?>, PParser<?>> parsers;130131static132{133parsers = new HashMap<Class<?>, PrimitiveParser.PParser<?>>(16);134parsers.put(Integer.class, new PParser<Integer>()135{136@Override Integer parse(String param) throws ParserException137{138if ( param.startsWith("0x") )139return Integer.parseInt(param.substring(2));140else141return Integer.valueOf(param);142}143});144parsers.put(Boolean.class, new PParser<Boolean>()145{146@Override Boolean parse(String param) throws ParserException147{148//special behavior for options149if(param == null) return true;150if(param.trim().length()==0) return true;151return Boolean.valueOf(param);152}153});154155parsers.put(String.class, new PParser<String>()156{157@Override String parse(String param) throws ParserException158{159if(param == null) throw new ParserException(" Got null value string.");160return param;161}162});163164165parsers.put(Character.class, new PParser<Character>()166{167@Override Character parse(String param) throws ParserException168{169if(param.length()!=1)170throw new TestBug("Found Character type option of length != 1");171return Character.valueOf(param.charAt(0));172}173});174175parsers.put(Byte.class, new PParser<Byte>()176{177@Override Byte parse(String param) throws ParserException178{179if ( param.startsWith("0x") )180return Byte.parseByte(param.substring(2));181else182return Byte.valueOf(param);183}184});185186parsers.put(Short.class, new PParser<Short>()187{188@Override Short parse(String param) throws ParserException189{190if ( param.startsWith("0x") )191return Short.parseShort(param.substring(2));192else193return Short.valueOf(param);194}195});196197parsers.put(Long.class, new PParser<Long>()198{199@Override Long parse(String param) throws ParserException200{201if ( param.startsWith("0x") )202return Long.parseLong(param.substring(2));203else204return Long.valueOf(param);205}206});207208parsers.put(Float.class, new PParser<Float>()209{210@Override Float parse(String param) throws ParserException211{212return Float.valueOf(param);213}214});215216parsers.put(Double.class, new PParser<Double>()217{218@Override Double parse(String param) throws ParserException219{220return Double.valueOf(param);221}222});223}224225226/* Discussion227* 1. It was proposed to use instead of the convertPrimitive the following228*229* private static Map<Class<?>, Class<?>> wrapperClasses = new HashMap<Class<?>, Class<?>>();230*231* so we could do if(type.isPrimitive())232type = wrapperClasses.get(type);233static {234wrapperClasses.put(boolean.class, Boolean.class);235wrapperClasses.put(short.class, Short.class);236wrapperClasses.put(int.class, Integer.class);237wrapperClasses.put(Long.Type, Long.class); // we can do it this way!238wrapperClasses.put(float.class, Float.class);239wrapperClasses.put(double.class, Double.class);240}241* The alternative is to register PParsers with corresponding Primitive type too.242*243* Also canHandle() could use244return wrapperClasses.keySet().contains(type) || wrapperClasses.entrySet().contains(type);245246* 2. Parsing can be implemented via reflection247return type.getMethod("valueOf", new Class[]{String.class}).invoke(null, string);248249* I don't like using reflection as it prevents optimisation,250* also now Strings and Characters are handled in a nice fashion.251*252* As for convertToPrimitive trick both ways are good,253* but current looks more generic though tricky254*/255256//// some test, should it be commented out?257// public static void main(String[] args)258// {259// try260// {261// String str = "0";262// Object o = null;263// str = "0";264// o = parse(str, String.class);265// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");266//267// str = "0";268// o = parse(str, int.class);269// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");270// str = "0";271// o = parse(str, Integer.class);272// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");273//274// str = "0,1,2";275// o = parse(str, int[].class);276// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + (int[]) o + "#");277// System.out.println("DATA:" + java.util.Arrays.toString((int[])o));278// // System.out.println("DATA:" + java.util.Arrays.deepToString( (int[]) o));279//280// str = "0";281// o = parse(str, byte.class);282// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");283//284// str = "0";285// o = parse(str, HashMap.class);286// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");287//// String str = "0"; Object o = parsePrimitiveString(help_option, type); System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");288// } catch (ParserException ex)289// {290// System.out.println("" +ex);291// }292//// String str = "0"; Object o = parsePrimitiveString(help_option, type); System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");293//294// }295296}297298299