Skip to content

Instantly share code, notes, and snippets.

@rbrick
Last active August 29, 2015 14:24
Show Gist options
  • Save rbrick/9919b645f0bc2be43670 to your computer and use it in GitHub Desktop.
Save rbrick/9919b645f0bc2be43670 to your computer and use it in GitHub Desktop.
Parse strings and inject them as parameters into methods
public interface Binder<B, T> {
Binder<B, T> bind(B bind);
void to(T to);
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Default {
String value();
}
public class MethodParser {
private Method method;
private ParametricRegistry registry;
public MethodParser(Method method, ParametricRegistry registry) {
this.method = method;
this.registry = registry;
}
public Method getMethod() {
return method;
}
public ParametricRegistry getRegistry() {
return registry;
}
/**
* @return A list of {@link Parameter}s
*/
public List<Parameter> parse() {
List<Parameter> parameters = new ArrayList<>();
for (int i = 0; i < method.getParameterCount(); i++) {
Parameter lp = new Parameter(method.getParameterTypes()[i], method.getParameterAnnotations()[i], registry,
method.getParameters()[i].getName(), i);
parameters.add(lp);
}
return parameters;
}
}
public class Parameter {
private Class<?> type;
private ParametricRegistry registry;
private List<Annotation> annotations;
private int index;
private String name;
public Parameter(Class<?> type, Annotation[] annotations, ParametricRegistry registry, String name, int index) {
this.type = type;
this.annotations = Arrays.asList(annotations);
this.registry = registry;
this.index = index;
this.name = name;
}
public Class<?> getType() {
return type;
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
boolean found = false;
for (Annotation anno : annotations) {
if (anno.annotationType() == annotation) {
found = true;
}
}
return found;
}
public Annotation getAnnotation(final Class<? extends Annotation> annotation) {
if (isAnnotationPresent(annotation)) {
return annotations.stream().filter((a) -> a.annotationType() == annotation)
.findFirst().orElseThrow(() -> new IllegalArgumentException("Could not find annotation!"));
}
return null;
}
public int getIndex() {
return index;
}
public int getArgumentIndex() {
return index - 1;
}
public boolean hasText() {
return isAnnotationPresent(Text.class);
}
public boolean hasDefault() {
return isAnnotationPresent(Default.class);
}
public String getDefault() {
if (hasDefault()) {
Default defaultV = (Default) getAnnotation(Default.class);
return defaultV.value();
}
return null;
}
public String getName() {
return name;
}
public Object parse(String argument) {
return registry.get(type).resolve(argument);
}
}
public interface ParameterResolver<T> {
T resolve(String argument);
}
public class ParametricParser {
private List<Parameter> parameters;
public ParametricParser(List<Parameter> parameters) {
this.parameters = parameters;
}
public ParsedResult parse(Object sender, Arguments arguments) {
boolean wasSuccess = true;
List<Object> objects = new ArrayList<>();
objects.add(sender);
for (Parameter parameter : parameters) {
Object obj = null;
if (arguments.get(parameter.getArgumentIndex()) == null) {
if (parameter.hasDefault()) {
obj = parameter.parse(parameter.getDefault());
} else {
wasSuccess = false;
}
} else {
obj = parameter.parse(arguments.get(parameter.getArgumentIndex()));
}
// is continuous
if (parameter.hasText()) {
if (arguments.get(parameter.getArgumentIndex()) != null) {
obj = arguments.join(parameter.getArgumentIndex());
}
objects.add(obj);
break;
} else if (parameter.getType().isPrimitive()) {
if (Number.class.isAssignableFrom(parameter.getType())) {
obj = PrimitiveUtils.toPrimitiveNumber((Number) obj);
} else if (Boolean.class.isAssignableFrom(parameter.getType())) {
obj = PrimitiveUtils.toPrimitiveBoolean((Boolean) obj);
}
}
objects.add(obj);
}
return new ParsedResult(objects.toArray(), wasSuccess);
}
public class ParsedResult {
private Object[] objects;
private boolean successful;
public ParsedResult(Object[] objects, boolean successful) {
this.objects = objects;
this.successful = successful;
}
public boolean isSuccessful() {
return successful;
}
public Object[] getObjects() {
return objects;
}
}
}
public class ParametricRegistry implements Binder<Class<?>, ParameterResolver<?>> {
private Map<Class<?>, ParameterResolver<?>> currentBindings = new HashMap<Class<?>, ParameterResolver<?>>();
private Class<?> currentBind = null;
public ParametricRegistry() {
bind(String.class).to(argument -> argument);
bind(Integer.TYPE).to(argument -> {
int parsed = 0;
try {
parsed = Integer.parseInt(argument);
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
return parsed;
});
bind(Integer.class).to(currentBindings.get(Integer.TYPE));
bind(Float.TYPE).to(argument -> {
float parsed = 0;
try {
parsed = Float.parseFloat(argument);
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
return parsed;
});
bind(Float.class).to(currentBindings.get(Float.TYPE));
bind(Double.TYPE).to(argument -> {
Double parsed = 0d;
try {
parsed = Double.parseDouble(argument);
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
return parsed;
});
bind(Double.class).to(currentBindings.get(Double.TYPE));
bind(Long.TYPE).to(argument -> {
Long parsed = 0L;
try {
parsed = Long.parseLong(argument);
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
return parsed;
});
bind(Long.class).to(currentBindings.get(Long.TYPE));
bind(Byte.TYPE).to(argument -> {
Byte parsed = 0x0;
try {
parsed = Byte.parseByte(argument);
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
return parsed;
});
bind(Byte.class).to(currentBindings.get(Byte.TYPE));
bind(Boolean.TYPE).to(argument -> {
boolean parsed = false;
if (argument.equalsIgnoreCase("true") || argument.equalsIgnoreCase("yes")) {
parsed = true;
} else if (argument.equalsIgnoreCase("false") || argument.equalsIgnoreCase("no")) {
parsed = false;
}
return parsed;
});
bind(Boolean.class).to(currentBindings.get(Boolean.TYPE));
}
public Binder<Class<?>, ParameterResolver<?>> bind(Class<?> bind) {
this.currentBind = bind;
return this;
}
public void to(ParameterResolver<?> to) {
if (currentBind == null) {
throw new IllegalArgumentException("currentBind is null!");
} else {
currentBindings.put(currentBind, to);
currentBind = null;
}
}
public Map<Class<?>, ParameterResolver<?>> getBindings() {
return currentBindings;
}
public ParameterResolver<?> get(Class<?> clazz) {
if (!currentBindings.containsKey(clazz)) {
throw new IllegalArgumentException("Could not find resolver for " + clazz.getSimpleName() + ".class");
}
return currentBindings.get(clazz);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Text {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment