/* * 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. */ /** * This framework allows one to automate parsing of the test command line * arguments (it automatically sets the corresponding fields of the * test class).
> java Test -iterations 10or via
java Testin the last case iterations defaults to 100.
We want to achieve this by annotating fields of the Test class by a special @Option annotation.
For simplicity suppose @Option is defined as follows:
@interface Option { //here all the annotation fields are mandatory String name(); String default(); String description(); }The test class uses an API like:
public class OptionSupport { public static void setup(Object test, String[] args); }Now a simple example:
public class Test { @Option( name="iterations", default="100", description="Number of iterations") int iterations; public void run() { // ..do actual testing here.. } public static void main(String args) { Test test = new Test(); OptionsSupport.setup(test, args); // instead of manually // parsing arguments // now test.iterations is set to 10 or 100. test.run(); } }This test can be also run via
- java Test -helpThen OptionSupport.setup() shows help and exits (by throwing exception?):
Supported options: -iterationsWe also want to be able to apply this to fields of non-simple types (via factories) and to other classes recursively (see @Options annotation below).Number of iterations (mandatory)
Please, see {@link vm.share.options.test.SimpleExample} for a working version of this. *
public class StressOptions { // [2] @Option(name="stressTime", default_value="60", description="Stress time") private long stressTime; ... }
we want to use command line like
java Test -stressTime 50here 50 is passed to the StressOptions.stressTime field. see {@link vm.share.options.Options} below.
public class Test { // [1] @Options StressOptions stressOptions = new StressOptions(); // [2] @Option(name="iterations", default_value="100", description="Number of iterations") int iterations; // [3] @Option( name="garbageProducer", default="byteArr", description="Garbage producer", factory="nsk.share.gc.gp.GarbageProducerFactory") GarbageProducer garbageProducer; ... // [4] @Option(name="logger", description="Logger", factory="nsk.share.log.LogFactory") Log log; public void run() { log.info("Start test"); log.info("Finish test"); } public static void main(String[] args) { Test test = new Test(); OptionsSupport.setup(test, args); test.run(); } }
The API is invoked via a call to {@link vm.share.options.OptionSupport#setup(Object, String[])}). Also there is {@link vm.share.options.OptionSupport#setup(Object, String[], OptionHandler)}) method. It allows the caller to pass a handler which takes care of the options not defined via @Option annotation.
- The following field types are supported out-of-box: [2]
All non-static fields (including private and protected) of class and it's superclasses are scanned for annotations.
(Possibly) Same annotations for setter methods ? (NOT IMPLEMENTED)
It is possible to inherit options of the field type through @Options annotations, see {@link vm.share.options.Options}, and [1] above.
Option.name defaults to the name of the field.
Object options are supported using {@link vm.share.options.OptionObjectFactory}, see [3] above. Please see {@link vm.share.options.OptionObjectFactory} interface, it should be implemented by the user and specified in the Option.factory attribute.
As a shortcut we provide BasicOptionObjectFactory class, which allows user to create a factory via @{@link vm.share.options.Factory} annotation:
@Factory ( placeholder_text="garbage producer", //used for generating <..> in the help message default_value="byteArr", classlist={ @FClass(key="byteArr", type="nsk.share.gc.gp.array.ByteArrayProducer", description="byte array producer") @FClass(key="charArr", type="nsk.share.gc.gp.array.CharArrayProducer", description="char array producer") ... } ) public class GarbageProducerFactory extends BasicOptionObjectFactory { }
If there is no unknownOptionHandler then in case of unsupported option, a Runtime exception is thrown.
If there is no 'default' annotation attribute and there is no default for OptionObjectFactory, then option is mandatory and a Runtime exception is thrown if it's missing.
Both '-option value' and '-option=value' formats are supported.
If main class is given '-help', OptionSupport.setup() shows help and exits (by throwing a Runtime exception):
Supported options: -iterationsNumber of iterations (mandatory) -stressTime Stress time (default 60) -garbageProducer Garbage producer (default byteArr). Supported keys: byteArr byte array producer charArr char array producer ... ...
The object created via factory is also scanned for @Option annotations
(like in the @Options case), i.e. it inherits options from the Test class.