Skip to content

Instantly share code, notes, and snippets.

@manoelcampos
Last active May 16, 2020 18:58
Show Gist options
  • Save manoelcampos/36c0b64b1664feb8b7dfb765c6747220 to your computer and use it in GitHub Desktop.
Save manoelcampos/36c0b64b1664feb8b7dfb765c6747220 to your computer and use it in GitHub Desktop.
A generic class that uses reflection to show how to get String values from an array and return such values converted to the generic type.
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
public class Option1<T>{
private int length;
private String defaultValue;
private Class<T> klass;
private Constructor construct;
public Option1(final Class<T> klass){
this.klass = klass;
try{
this.construct = klass.getConstructor(new Class[]{String.class});
} catch(NoSuchMethodException e){
throw new RuntimeException(
"There is no way to convert option values from String to " + klass.getSimpleName() +
": " + e.getMessage());
}
}
public T getFirstValue(final String[] values){
return getValues(values)[0];
}
/**
* Gets the values of the option, excluding the option name (the 0th element).
* @return an array containing the values (without the 0th element), if the values' length isn't as expected;
* or an array containing the default value if the length isn't as expected and there is a default value.
* @throws IllegalStateException when the length of values isn't as expected and there isn't a default value
*/
public T[] getValues(final String[] values){
if(defaultValue == null && values.length != length){
throw new IllegalStateException("Wrong option line passed, string options do only have 2 values");
}
if(values.length == length) {
return createGenericArray(values, 1);
}
return createGenericArray(new String[]{defaultValue});
}
private T[] createGenericArray(final String[] values){
return createGenericArray(values, 0);
}
@SuppressWarnings("unchecked")
private T[] createGenericArray(final String[] values, final int startInclusive){
final T[] array = (T[])Array.newInstance(klass, values.length-startInclusive);
//It was required to convert to list then to array in order to get an array of the generic type.
Arrays
.stream(values, startInclusive, values.length)
.map(this::convertFromString)
.collect(Collectors.toList())
.toArray(array);
return array;
}
@SuppressWarnings("unchecked")
private T convertFromString(final String value){
//if the generic type is already String, there is not need for conversion
if(klass == String.class){
return (T)value;
}
try {
return (T)construct.newInstance(value);
} catch(InstantiationException|IllegalAccessException|InvocationTargetException e){
throw new RuntimeException(
"Error trying to convert option value '"+value+"' from String to " + klass.getSimpleName() +
": " + e.getMessage());
}
}
/* Trying the implementation. */
public static void main(String[] args) {
System.out.println();
Option1<String> strOpt = new Option1<>(String.class);
strOpt.length = 3;
String[] values = new String[]{"-o", "1", "2"};
System.out.println("First String Value: " + strOpt.getFirstValue(values));
System.out.println("String Values: " + Arrays.toString(strOpt.getValues(values)));
try{
values = new String[]{"-o", "1"};
//Error because the length of values isn't equal to 3
System.out.println("First String Value: " + strOpt.getFirstValue(values));
} catch(Exception e){
System.out.println("\nError: " + e.getMessage() + "\n");
}
strOpt.length = 2;
strOpt.defaultValue = "default value";
values = new String[]{"-o"};
System.out.println("First String Value: " + strOpt.getFirstValue(values));
System.out.println("String Values: " + Arrays.toString(strOpt.getValues(values)) + "\n");
Option1<Integer> intOpt = new Option1<>(Integer.class);
intOpt.length = 3;
values = new String[]{"-o", "1", "2"};
System.out.println("\nFirst Int Value: " + intOpt.getFirstValue(values));
Integer[] intValues = intOpt.getValues(values);
System.out.println("Int Values: ");
for(Integer i: intValues){
System.out.println(i);
}
System.out.println();
values = new String[]{"-o", "99", "this value isn't a number and will throw an exception"};
try {
System.out.println("First Int Value: " + intOpt.getFirstValue(values));
intValues = intOpt.getValues(values);
System.out.println("Int Values: ");
for(Integer i: intValues){
System.out.println(i);
}
}catch(RuntimeException e){
System.out.println(e.getMessage());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment