From 2024fb3e32daaaa725a601af30e40710134f541a Mon Sep 17 00:00:00 2001 From: hanna Date: Fri, 24 Jul 2009 22:15:57 +0000 Subject: [PATCH] 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 --- .../sting/gatk/CommandLineExecutable.java | 6 +- .../sting/utils/cmdLine/ArgumentFactory.java | 2 +- .../sting/utils/cmdLine/ArgumentSource.java | 26 +++- .../utils/cmdLine/ArgumentTypeDescriptor.java | 140 +++++++----------- .../sting/utils/cmdLine/ParsingEngine.java | 28 +--- 5 files changed, 79 insertions(+), 123 deletions(-) diff --git a/java/src/org/broadinstitute/sting/gatk/CommandLineExecutable.java b/java/src/org/broadinstitute/sting/gatk/CommandLineExecutable.java index 38f7a6131..a4063881d 100644 --- a/java/src/org/broadinstitute/sting/gatk/CommandLineExecutable.java +++ b/java/src/org/broadinstitute/sting/gatk/CommandLineExecutable.java @@ -153,9 +153,9 @@ public abstract class CommandLineExecutable extends CommandLineProgram { @Override protected ArgumentFactory getCustomArgumentFactory() { return new ArgumentFactory() { - public Object createArgument( Class type, List repr ) { - if (type == SAMFileReader.class && repr.size() == 1) { - SAMFileReader samFileReader = new SAMFileReader(new File(repr.get(0)),true); + public Object createArgument( Class type, String... repr ) { + if (type == SAMFileReader.class && repr.length == 1) { + SAMFileReader samFileReader = new SAMFileReader(new File(repr[0]),true); samFileReader.setValidationStringency(getArgumentCollection().strictnessLevel); return samFileReader; } diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentFactory.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentFactory.java index 1b81eacc2..fa056e2a8 100755 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentFactory.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentFactory.java @@ -38,5 +38,5 @@ public abstract class ArgumentFactory { * @param repr A String representation of the argument. * @return */ - public abstract Object createArgument(Class type, List repr); + public abstract Object createArgument(Class type, String... repr); } diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentSource.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentSource.java index 78d016b90..038d71f62 100644 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentSource.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentSource.java @@ -119,11 +119,26 @@ public class ArgumentSource { } /** - * Set the value of the field in the passed object to value - * @param targetInstance Instance in which to find the field. - * @param value Value to which to set the field. + * Injects the specified value into the selected field of the instance. + * @param targetInstance Instance into which to inject the parsed value. + * @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 { field.setAccessible(true); field.set(targetInstance, value); @@ -132,7 +147,6 @@ public class ArgumentSource { //logger.fatal("processArgs: cannot convert field " + field.toString()); throw new StingException("processArgs: Failed conversion " + ex.getMessage(), ex); } - } /** @@ -151,6 +165,4 @@ public class ArgumentSource { Class argumentType = field.getType(); return Collection.class.isAssignableFrom(argumentType) || field.getType().isArray(); } - - } diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentTypeDescriptor.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentTypeDescriptor.java index f1f227441..fc714324b 100644 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentTypeDescriptor.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentTypeDescriptor.java @@ -44,53 +44,46 @@ public abstract class ArgumentTypeDescriptor { * our log, which we want to capture anything from org.broadinstitute.sting */ 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 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 { - 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 ) { - super( field ); - this.type = field.getType(); + try { + type.getConstructor(String.class); + 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 ) { - super( fieldName ); - this.type = type; - } - - public Object parse( String... values ) { + @Override + public Object parse( Field field, Class type, String... values ) { if( values.length > 1 ) throw new StingException("Simple argument parser is unable to parse multiple arguments."); @@ -109,16 +102,12 @@ class SimpleArgumentTypeDescriptor extends ArgumentTypeDescriptor { } } catch (NoSuchMethodException e) { - logger.fatal("ArgumentParser: NoSuchMethodException: cannot convert field " + fieldName); throw new StingException("constructFromString:NoSuchMethodException: Failed conversion " + e.getMessage()); } catch (IllegalAccessException e) { - logger.fatal("ArgumentParser: IllegalAccessException: cannot convert field " + fieldName); throw new StingException("constructFromString:IllegalAccessException: Failed conversion " + e.getMessage()); } catch (InvocationTargetException e) { - logger.fatal("ArgumentParser: InvocationTargetException: cannot convert field " + fieldName); throw new StingException("constructFromString:InvocationTargetException: Failed conversion " + e.getMessage()); } catch (InstantiationException e) { - logger.fatal("ArgumentParser: InstantiationException: cannot convert field " + fieldName); throw new StingException("constructFromString:InstantiationException: Failed conversion " + e.getMessage()); } @@ -143,27 +132,28 @@ class SimpleArgumentTypeDescriptor extends ArgumentTypeDescriptor { } class CompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor { - private final Class type; - private final Class componentType; - private final ArgumentTypeDescriptor componentArgumentParser; + @Override + public boolean supports( Class type ) { + 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 ) { - super( field ); - Class candidateType = field.getType(); - - if( Collection.class.isAssignableFrom(candidateType) ) { + if( Collection.class.isAssignableFrom(type) ) { // 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. - 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; - else if( java.util.Queue.class.isAssignableFrom(candidateType) ) candidateType = java.util.ArrayDeque.class; - else if( java.util.Set.class.isAssignableFrom(candidateType) ) candidateType = java.util.TreeSet.class; + if( java.util.List.class.isAssignableFrom(type) ) type = ArrayList.class; + else if( java.util.Queue.class.isAssignableFrom(type) ) type = java.util.ArrayDeque.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( field.getGenericType() instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType)field.getGenericType(); @@ -174,52 +164,30 @@ class CompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor { else 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() ) { - this.componentType = type.getComponentType(); + componentType = type.getComponentType(); } else 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) ) { Collection collection = null; try { collection = (Collection)type.newInstance(); } 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()); } 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()); } for( String value: values ) - collection.add( componentArgumentParser.parse(value) ); + collection.add( componentArgumentParser.parse(field,componentType,value) ); return collection; } @@ -227,7 +195,7 @@ class CompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor { Object arr = Array.newInstance(componentType,values.length); 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; } diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java index 1eeaa82ab..e7a8f43d8 100755 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java @@ -270,21 +270,8 @@ public class ParsingEngine { return; if( definition.source.clazz.isAssignableFrom(object.getClass()) ) { - if( customArgumentFactory != null ) { - Object instance = customArgumentFactory.createArgument(definition.source.field.getType(), match.values()); - 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 ); + String[] tokens = match.values().toArray(new String[0]); + definition.source.inject( customArgumentFactory, object, tokens ); } } @@ -347,17 +334,6 @@ public class ParsingEngine { // No parse results found. 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 strs) { - ArgumentTypeDescriptor fieldParser = ArgumentTypeDescriptor.create(f); - return fieldParser.parse( strs.toArray(new String[0]) ); - } } /**