GeneratorUtil.java
package net.morimekta.terminal.args.impl;
import net.morimekta.strings.NamingUtil;
import net.morimekta.terminal.args.ArgException;
import net.morimekta.terminal.args.ValueParser;
import net.morimekta.terminal.args.annotations.ArgIsHidden;
import net.morimekta.terminal.args.annotations.ArgIsRepeated;
import net.morimekta.terminal.args.annotations.ArgIsRequired;
import net.morimekta.terminal.args.annotations.ArgKeyParser;
import net.morimekta.terminal.args.annotations.ArgOptions;
import net.morimekta.terminal.args.annotations.ArgValueParser;
import net.morimekta.terminal.args.reference.Reference;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Supplier;
public final class GeneratorUtil {
private GeneratorUtil() {}
public static Optional<Field> findField(Class<?> type, String name) {
try {
return Optional.of(type.getDeclaredField(name));
} catch (NoSuchFieldException e) {
// And in case someone makes non-standard naming of public fields.
for (Field field : type.getDeclaredFields()) {
var reFormatted = NamingUtil.format(field.getName(), NamingUtil.Format.CAMEL);
if (name.equals(reFormatted)) {
return Optional.of(field);
}
}
return Optional.empty();
}
}
public static Optional<Method> findMethod(Class<?> type, String name, Class<?>... params) {
try {
return Optional.of(type.getDeclaredMethod(name, params));
} catch (NoSuchMethodException e) {
return Optional.empty();
}
}
public static <T extends Annotation> T getAnnotation(Class<?> type, Class<T> annotation) {
if (type.isAnnotationPresent(annotation)) {
return type.getAnnotation(annotation);
}
if (type.getSuperclass() != null) {
T out = getAnnotation(type.getSuperclass(), annotation);
if (out != null) {
return out;
}
}
for (Class<?> iFace : type.getInterfaces()) {
T out = getAnnotation(iFace, annotation);
if (out != null) {
return out;
}
}
return null;
}
public static boolean isPublic(Method accessibleObject) {
return (accessibleObject.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC;
}
public static boolean isStatic(Method accessibleObject) {
return (accessibleObject.getModifiers() & Modifier.STATIC) == Modifier.STATIC;
}
public static String getShortName(Reference ref) {
if (ref.isAnnotationPresent(ArgOptions.class)) {
var opt = ref.getAnnotation(ArgOptions.class);
if (opt.shortChar() != '\0') {
return "" + opt.shortChar();
}
}
return "";
}
public static char getShortChar(Reference ref) {
if (ref.isAnnotationPresent(ArgOptions.class)) {
var opt = ref.getAnnotation(ArgOptions.class);
if (opt.shortChar() != '\0') {
return opt.shortChar();
}
}
return '\0';
}
public static String getUsage(Reference ref) {
if (ref.isAnnotationPresent(ArgOptions.class)) {
var usage = ref.getAnnotation(ArgOptions.class).usage();
if (!usage.isEmpty()) {
return usage;
}
}
return ref.getUsage();
}
public static Supplier<Map<Object, Object>> createMapSupplier(Class<?> type) {
if (type == SortedMap.class ||
type == NavigableMap.class) {
return TreeMap::new;
} else if (type == Map.class) {
return HashMap::new;
}
if ((type.getModifiers() & Modifier.ABSTRACT) == 0 &&
!type.isInterface()) {
try {
@SuppressWarnings("unchecked")
var constructor = (Constructor<Map<Object, Object>>) type.getConstructor();
if (!constructor.canAccess(null)) {
throw new IllegalArgumentException("Unable to access default constructor for " + type.getName());
}
return () -> {
try {
return constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new ArgException("Unable to instantiate %s", type.getName(), e);
}
};
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Unable to find default constructor for " + type.getName(), e);
}
}
throw new IllegalArgumentException("Unable to determine constructor for " + type.getName());
}
public static Supplier<Collection<Object>> createCollectionSupplier(Class<?> type) {
if (type == NavigableSet.class ||
type == SortedSet.class) {
return TreeSet::new;
} else if (type == Set.class) {
return HashSet::new;
} else if (type == List.class ||
type == Collection.class) {
return ArrayList::new;
}
if ((type.getModifiers() & Modifier.ABSTRACT) == 0 &&
!type.isInterface()) {
try {
@SuppressWarnings("unchecked")
var constructor = (Constructor<Collection<Object>>) type.getConstructor();
if (!constructor.canAccess(null)) {
throw new IllegalArgumentException("Unable to access default constructor for " + type.getName());
}
return () -> {
try {
return constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new ArgException("Unable to instantiate %s", type.getName(), e);
}
};
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Unable to find default constructor for " + type.getName(), e);
}
}
throw new IllegalArgumentException("Unable to determine constructor for " + type.getName());
}
@SuppressWarnings("unchecked")
public static ValueParser<Object> getKeyParser(Class<?> type, Reference ref) {
if (ref.isAnnotationPresent(ArgKeyParser.class)) {
return (ValueParser<Object>) getAnnotationParser(ref.getAnnotation(ArgKeyParser.class).value());
}
if (type.isAnnotationPresent(ArgValueParser.class)) {
return (ValueParser<Object>) getAnnotationParser(type.getAnnotation(ArgValueParser.class).value());
}
return (ValueParser<Object>) ValueParser.defaultParser(type).orElse(null);
}
@SuppressWarnings("unchecked")
public static ValueParser<Object> getValueParser(Class<?> type, Reference ref) {
if (ref.isAnnotationPresent(ArgValueParser.class)) {
return (ValueParser<Object>) getAnnotationParser(ref.getAnnotation(ArgValueParser.class).value());
}
if (type.isAnnotationPresent(ArgValueParser.class)) {
return (ValueParser<Object>) getAnnotationParser(type.getAnnotation(ArgValueParser.class).value());
}
return (ValueParser<Object>) ValueParser.defaultParser(type).orElse(null);
}
public static boolean isDeclared(Reference ref) {
return ref.isAnnotationPresent(ArgOptions.class) ||
ref.isAnnotationPresent(ArgKeyParser.class) ||
ref.isAnnotationPresent(ArgValueParser.class) ||
ref.isAnnotationPresent(ArgIsRequired.class) ||
ref.isAnnotationPresent(ArgIsRepeated.class) ||
ref.isAnnotationPresent(ArgIsHidden.class);
}
public static boolean isDeclared(AccessibleObject object) {
return object.isAnnotationPresent(ArgOptions.class) ||
object.isAnnotationPresent(ArgKeyParser.class) ||
object.isAnnotationPresent(ArgValueParser.class) ||
object.isAnnotationPresent(ArgIsRequired.class) ||
object.isAnnotationPresent(ArgIsRepeated.class) ||
object.isAnnotationPresent(ArgIsHidden.class);
}
public static ValueParser<?> getAnnotationParser(Class<? extends ValueParser<?>> type) {
try {
return type.getConstructor().newInstance();
} catch (InstantiationException |
IllegalAccessException |
NoSuchMethodException |
InvocationTargetException e) {
throw new IllegalArgumentException("Invalid value parser: " + type.getName(), e);
}
}
public static ValueParser<?> getValueParser(Class<?> type) {
return ValueParser.defaultParser(type).orElse(null);
}
}