Better division of responsibilities between sources and type descriptors.
git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@1314 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
parent
64221907a2
commit
2024fb3e32
|
|
@ -153,9 +153,9 @@ public abstract class CommandLineExecutable extends CommandLineProgram {
|
||||||
@Override
|
@Override
|
||||||
protected ArgumentFactory getCustomArgumentFactory() {
|
protected ArgumentFactory getCustomArgumentFactory() {
|
||||||
return new ArgumentFactory() {
|
return new ArgumentFactory() {
|
||||||
public Object createArgument( Class type, List<String> repr ) {
|
public Object createArgument( Class type, String... repr ) {
|
||||||
if (type == SAMFileReader.class && repr.size() == 1) {
|
if (type == SAMFileReader.class && repr.length == 1) {
|
||||||
SAMFileReader samFileReader = new SAMFileReader(new File(repr.get(0)),true);
|
SAMFileReader samFileReader = new SAMFileReader(new File(repr[0]),true);
|
||||||
samFileReader.setValidationStringency(getArgumentCollection().strictnessLevel);
|
samFileReader.setValidationStringency(getArgumentCollection().strictnessLevel);
|
||||||
return samFileReader;
|
return samFileReader;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,5 +38,5 @@ public abstract class ArgumentFactory {
|
||||||
* @param repr A String representation of the argument.
|
* @param repr A String representation of the argument.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract Object createArgument(Class type, List<String> repr);
|
public abstract Object createArgument(Class type, String... repr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,11 +119,26 @@ public class ArgumentSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the value of the field in the passed object to <code>value</code>
|
* Injects the specified value into the selected field of the instance.
|
||||||
* @param targetInstance Instance in which to find the field.
|
* @param targetInstance Instance into which to inject the parsed value.
|
||||||
* @param value Value to which to set the field.
|
* @param values String representation of all values passed.
|
||||||
*/
|
*/
|
||||||
public void setValue( Object targetInstance, Object value ) {
|
public void inject( ArgumentFactory customArgumentFactory, Object targetInstance, String... values ) {
|
||||||
|
Object value = null;
|
||||||
|
|
||||||
|
if( customArgumentFactory != null ) {
|
||||||
|
value = customArgumentFactory.createArgument(field.getType(), values);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( value == null ) {
|
||||||
|
if( !isFlag() ) {
|
||||||
|
ArgumentTypeDescriptor typeDescriptor = ArgumentTypeDescriptor.create( field.getType() );
|
||||||
|
value = typeDescriptor.parse( field, field.getType(), values );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
value = true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(targetInstance, value);
|
field.set(targetInstance, value);
|
||||||
|
|
@ -132,7 +147,6 @@ public class ArgumentSource {
|
||||||
//logger.fatal("processArgs: cannot convert field " + field.toString());
|
//logger.fatal("processArgs: cannot convert field " + field.toString());
|
||||||
throw new StingException("processArgs: Failed conversion " + ex.getMessage(), ex);
|
throw new StingException("processArgs: Failed conversion " + ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -151,6 +165,4 @@ public class ArgumentSource {
|
||||||
Class argumentType = field.getType();
|
Class argumentType = field.getType();
|
||||||
return Collection.class.isAssignableFrom(argumentType) || field.getType().isArray();
|
return Collection.class.isAssignableFrom(argumentType) || field.getType().isArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,53 +44,46 @@ public abstract class ArgumentTypeDescriptor {
|
||||||
* our log, which we want to capture anything from org.broadinstitute.sting
|
* our log, which we want to capture anything from org.broadinstitute.sting
|
||||||
*/
|
*/
|
||||||
protected static Logger logger = Logger.getLogger(ArgumentTypeDescriptor.class);
|
protected static Logger logger = Logger.getLogger(ArgumentTypeDescriptor.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the field which should be parsed by this argument.
|
|
||||||
*/
|
|
||||||
protected final String fieldName;
|
|
||||||
|
|
||||||
public static ArgumentTypeDescriptor create( Field field ) {
|
|
||||||
Class type = field.getType();
|
|
||||||
|
|
||||||
if( Collection.class.isAssignableFrom(type) || type.isArray() )
|
|
||||||
return new CompoundArgumentTypeDescriptor( field );
|
|
||||||
else
|
|
||||||
return new SimpleArgumentTypeDescriptor( field );
|
|
||||||
}
|
|
||||||
|
|
||||||
static ArgumentTypeDescriptor create( String fieldName, Class type ) {
|
|
||||||
if( Collection.class.isAssignableFrom(type) || type.isArray() )
|
|
||||||
return new CompoundArgumentTypeDescriptor( fieldName, type );
|
|
||||||
else
|
|
||||||
return new SimpleArgumentTypeDescriptor( fieldName, type );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ArgumentTypeDescriptor( Field field ) {
|
|
||||||
fieldName = field.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ArgumentTypeDescriptor( String fieldName ) {
|
|
||||||
this.fieldName = fieldName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Object parse( String... values );
|
/**
|
||||||
|
* Class reference to the different types of descriptors that the create method can create.
|
||||||
|
*/
|
||||||
|
private static List<ArgumentTypeDescriptor> descriptors = Arrays.asList( new SimpleArgumentTypeDescriptor(),
|
||||||
|
new CompoundArgumentTypeDescriptor() );
|
||||||
|
|
||||||
|
public static ArgumentTypeDescriptor create( Class type ) {
|
||||||
|
for( ArgumentTypeDescriptor descriptor: descriptors ) {
|
||||||
|
if( descriptor.supports(type) )
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
throw new StingException("Can't process command-line arguments of type: " + type.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean supports( Class type );
|
||||||
|
|
||||||
|
public abstract Object parse( Field field, Class type, String... values );
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimpleArgumentTypeDescriptor extends ArgumentTypeDescriptor {
|
class SimpleArgumentTypeDescriptor extends ArgumentTypeDescriptor {
|
||||||
private final Class type;
|
@Override
|
||||||
|
public boolean supports( Class type ) {
|
||||||
|
if( type.isPrimitive() ) return true;
|
||||||
|
if( type.isEnum() ) return true;
|
||||||
|
if( primitiveToWrapperMap.containsValue(type) ) return true;
|
||||||
|
|
||||||
public SimpleArgumentTypeDescriptor( Field field ) {
|
try {
|
||||||
super( field );
|
type.getConstructor(String.class);
|
||||||
this.type = field.getType();
|
return true;
|
||||||
|
}
|
||||||
|
catch( Exception ex ) {
|
||||||
|
// An exception thrown above means that the String constructor either doesn't
|
||||||
|
// exist or can't be accessed. In either case, this descriptor doesn't support this type.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimpleArgumentTypeDescriptor( String fieldName, Class type ) {
|
@Override
|
||||||
super( fieldName );
|
public Object parse( Field field, Class type, String... values ) {
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object parse( String... values ) {
|
|
||||||
if( values.length > 1 )
|
if( values.length > 1 )
|
||||||
throw new StingException("Simple argument parser is unable to parse multiple arguments.");
|
throw new StingException("Simple argument parser is unable to parse multiple arguments.");
|
||||||
|
|
||||||
|
|
@ -109,16 +102,12 @@ class SimpleArgumentTypeDescriptor extends ArgumentTypeDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e) {
|
catch (NoSuchMethodException e) {
|
||||||
logger.fatal("ArgumentParser: NoSuchMethodException: cannot convert field " + fieldName);
|
|
||||||
throw new StingException("constructFromString:NoSuchMethodException: Failed conversion " + e.getMessage());
|
throw new StingException("constructFromString:NoSuchMethodException: Failed conversion " + e.getMessage());
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
logger.fatal("ArgumentParser: IllegalAccessException: cannot convert field " + fieldName);
|
|
||||||
throw new StingException("constructFromString:IllegalAccessException: Failed conversion " + e.getMessage());
|
throw new StingException("constructFromString:IllegalAccessException: Failed conversion " + e.getMessage());
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
logger.fatal("ArgumentParser: InvocationTargetException: cannot convert field " + fieldName);
|
|
||||||
throw new StingException("constructFromString:InvocationTargetException: Failed conversion " + e.getMessage());
|
throw new StingException("constructFromString:InvocationTargetException: Failed conversion " + e.getMessage());
|
||||||
} catch (InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
logger.fatal("ArgumentParser: InstantiationException: cannot convert field " + fieldName);
|
|
||||||
throw new StingException("constructFromString:InstantiationException: Failed conversion " + e.getMessage());
|
throw new StingException("constructFromString:InstantiationException: Failed conversion " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,27 +132,28 @@ class SimpleArgumentTypeDescriptor extends ArgumentTypeDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor {
|
class CompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor {
|
||||||
private final Class type;
|
@Override
|
||||||
private final Class componentType;
|
public boolean supports( Class type ) {
|
||||||
private final ArgumentTypeDescriptor componentArgumentParser;
|
return ( Collection.class.isAssignableFrom(type) || type.isArray() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object parse( Field field, Class type, String... values )
|
||||||
|
{
|
||||||
|
Class componentType = null;
|
||||||
|
ArgumentTypeDescriptor componentArgumentParser;
|
||||||
|
|
||||||
public CompoundArgumentTypeDescriptor( Field field ) {
|
if( Collection.class.isAssignableFrom(type) ) {
|
||||||
super( field );
|
|
||||||
Class candidateType = field.getType();
|
|
||||||
|
|
||||||
if( Collection.class.isAssignableFrom(candidateType) ) {
|
|
||||||
|
|
||||||
// If this is a generic interface, pick a concrete implementation to create and pass back.
|
// If this is a generic interface, pick a concrete implementation to create and pass back.
|
||||||
// Because of type erasure, don't worry about creating one of exactly the correct type.
|
// Because of type erasure, don't worry about creating one of exactly the correct type.
|
||||||
if( Modifier.isInterface(candidateType.getModifiers()) || Modifier.isAbstract(candidateType.getModifiers()) )
|
if( Modifier.isInterface(type.getModifiers()) || Modifier.isAbstract(type.getModifiers()) )
|
||||||
{
|
{
|
||||||
if( java.util.List.class.isAssignableFrom(candidateType) ) candidateType = ArrayList.class;
|
if( java.util.List.class.isAssignableFrom(type) ) type = ArrayList.class;
|
||||||
else if( java.util.Queue.class.isAssignableFrom(candidateType) ) candidateType = java.util.ArrayDeque.class;
|
else if( java.util.Queue.class.isAssignableFrom(type) ) type = java.util.ArrayDeque.class;
|
||||||
else if( java.util.Set.class.isAssignableFrom(candidateType) ) candidateType = java.util.TreeSet.class;
|
else if( java.util.Set.class.isAssignableFrom(type) ) type = java.util.TreeSet.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.type = candidateType;
|
|
||||||
|
|
||||||
// If this is a parameterized collection, find the contained type. If blow up if only one type exists.
|
// If this is a parameterized collection, find the contained type. If blow up if only one type exists.
|
||||||
if( field.getGenericType() instanceof ParameterizedType) {
|
if( field.getGenericType() instanceof ParameterizedType) {
|
||||||
ParameterizedType parameterizedType = (ParameterizedType)field.getGenericType();
|
ParameterizedType parameterizedType = (ParameterizedType)field.getGenericType();
|
||||||
|
|
@ -174,52 +164,30 @@ class CompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor {
|
||||||
else
|
else
|
||||||
componentType = String.class;
|
componentType = String.class;
|
||||||
}
|
}
|
||||||
else if( candidateType.isArray() ) {
|
|
||||||
this.type = candidateType;
|
|
||||||
this.componentType = candidateType.getComponentType();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw new StingException("Unsupported compound argument type: " + candidateType);
|
|
||||||
|
|
||||||
componentArgumentParser = ArgumentTypeDescriptor.create( fieldName, componentType );
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompoundArgumentTypeDescriptor( String fieldName, Class type ) {
|
|
||||||
super(fieldName);
|
|
||||||
|
|
||||||
this.type = type;
|
|
||||||
|
|
||||||
if( Collection.class.isAssignableFrom(type) ) {
|
|
||||||
this.componentType = String.class;
|
|
||||||
}
|
|
||||||
else if( type.isArray() ) {
|
else if( type.isArray() ) {
|
||||||
this.componentType = type.getComponentType();
|
componentType = type.getComponentType();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new StingException("Unsupported compound argument type: " + type);
|
throw new StingException("Unsupported compound argument type: " + type);
|
||||||
|
|
||||||
componentArgumentParser = ArgumentTypeDescriptor.create( fieldName, componentType );
|
componentArgumentParser = ArgumentTypeDescriptor.create( componentType );
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object parse( String... values )
|
|
||||||
{
|
|
||||||
if( Collection.class.isAssignableFrom(type) ) {
|
if( Collection.class.isAssignableFrom(type) ) {
|
||||||
Collection collection = null;
|
Collection collection = null;
|
||||||
try {
|
try {
|
||||||
collection = (Collection)type.newInstance();
|
collection = (Collection)type.newInstance();
|
||||||
}
|
}
|
||||||
catch (InstantiationException e) {
|
catch (InstantiationException e) {
|
||||||
logger.fatal("ArgumentParser: InstantiationException: cannot convert field " + fieldName);
|
logger.fatal("ArgumentParser: InstantiationException: cannot convert field " + field.getName());
|
||||||
throw new StingException("constructFromString:InstantiationException: Failed conversion " + e.getMessage());
|
throw new StingException("constructFromString:InstantiationException: Failed conversion " + e.getMessage());
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException e) {
|
catch (IllegalAccessException e) {
|
||||||
logger.fatal("ArgumentParser: IllegalAccessException: cannot convert field " + fieldName);
|
logger.fatal("ArgumentParser: IllegalAccessException: cannot convert field " + field.getName());
|
||||||
throw new StingException("constructFromString:IllegalAccessException: Failed conversion " + e.getMessage());
|
throw new StingException("constructFromString:IllegalAccessException: Failed conversion " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
for( String value: values )
|
for( String value: values )
|
||||||
collection.add( componentArgumentParser.parse(value) );
|
collection.add( componentArgumentParser.parse(field,componentType,value) );
|
||||||
|
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +195,7 @@ class CompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor {
|
||||||
Object arr = Array.newInstance(componentType,values.length);
|
Object arr = Array.newInstance(componentType,values.length);
|
||||||
|
|
||||||
for( int i = 0; i < values.length; i++ )
|
for( int i = 0; i < values.length; i++ )
|
||||||
Array.set( arr,i,componentArgumentParser.parse(values[i]));
|
Array.set( arr,i,componentArgumentParser.parse(field,componentType,values[i]));
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,21 +270,8 @@ public class ParsingEngine {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( definition.source.clazz.isAssignableFrom(object.getClass()) ) {
|
if( definition.source.clazz.isAssignableFrom(object.getClass()) ) {
|
||||||
if( customArgumentFactory != null ) {
|
String[] tokens = match.values().toArray(new String[0]);
|
||||||
Object instance = customArgumentFactory.createArgument(definition.source.field.getType(), match.values());
|
definition.source.inject( customArgumentFactory, object, tokens );
|
||||||
if( instance != null ) {
|
|
||||||
definition.source.setValue( object, instance );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !definition.source.isFlag() ) {
|
|
||||||
String[] tokens = match.values().toArray(new String[0]);
|
|
||||||
ArgumentTypeDescriptor fieldParser = ArgumentTypeDescriptor.create(definition.source.field);
|
|
||||||
definition.source.setValue( object, fieldParser.parse(tokens) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
definition.source.setValue( object, true );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -347,17 +334,6 @@ public class ParsingEngine {
|
||||||
// No parse results found.
|
// No parse results found.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a command-line argument given a string and field.
|
|
||||||
* @param f Field type from which to infer the type.
|
|
||||||
* @param strs Collection of parameter strings to parse.
|
|
||||||
* @return Parsed object of the inferred type.
|
|
||||||
*/
|
|
||||||
private Object constructFromString(Field f, List<String> strs) {
|
|
||||||
ArgumentTypeDescriptor fieldParser = ArgumentTypeDescriptor.create(f);
|
|
||||||
return fieldParser.parse( strs.toArray(new String[0]) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue