class DefaultArgumentValueResolver implements ArgumentValueResolver {

    @Override
    public Object resolve(VariableResolver variableResolver, Argument argument) {
        if (argument instanceof Argument.Value) {
            return ((Argument.Value) argument).getValue();
        }
        if (argument instanceof Argument.Values) {
            return ((Argument.Values) argument).getArguments().stream()
                    .map(a -> resolve(variableResolver, a))
                    .collect(Collectors.toList());
        }
        if (argument instanceof Argument.Reference) {
            if (!(variableResolver instanceof PredicateContext)) {
                throw new IllegalArgumentException("Expected PredicateContext as VariableResolver");
            }
            Argument.Reference reference = (Argument.Reference) argument;
            String path = reference.getReference();
            int dotIndex = path.indexOf(".");
            if (dotIndex == -1) {
                return variableResolver.resolve(path);
            }
            String identifier = path.substring(0, dotIndex);
            path = path.substring(dotIndex + 1);
            Object resolvedValue = variableResolver.resolve(identifier);
            Class referenceType = TypeUtils.getRawType(reference.getReferenceType(), null);
            referenceType = resolvedValue != null && Object.class.equals(referenceType)
                    ? resolvedValue.getClass()
                    : referenceType;
            return FieldReferringClassFactory.create(referenceType, identifier, path).get((PredicateContext) variableResolver);
        }
        if (argument instanceof Argument.Invocation) {
            if (!(variableResolver instanceof ProcessingContext)) {
                throw new IllegalArgumentException("Expected ProcessingContext as VariableResolver");
            }
            ProcessingContext processingContext = (ProcessingContext) variableResolver;
            Invocation<ProcessingContext, Object> value = processingInvocationFactory.create((Argument.Invocation) argument);
            return value.proceed(processingContext);
        }

        throw new IllegalArgumentException(String.format("Unsupported argument type %s", argument.getClass()));
    }

    public  DefaultArgumentValueResolver(ProcessingInvocationFactory<Object> processingInvocationFactory);

}