/*
 * Copyright 2015, Yahoo Inc.
 * Copyrights licensed under the Apache 2.0 License.
 * See the accompanying LICENSE file for terms.
 */
package com.yahoo.squidb.sql;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Default implementation of {@link ArgumentResolver} that unwraps AtomicReferences, AtomicBooleans, and ThreadLocals
 */
public class DefaultArgumentResolver implements ArgumentResolver {

    @Override
    public Object resolveArgument(Object arg) {
        while (true) {
            if (arg instanceof AtomicReference) {
                arg = ((AtomicReference<?>) arg).get();
            } else if (arg instanceof AtomicBoolean) { // Not a subclass of Number so we need to unwrap it
                return ((AtomicBoolean) arg).get() ? 1 : 0;
            } else if (arg instanceof Enum<?>) {
                return ((Enum<?>) arg).name();
            } else if (arg instanceof ThreadLocal) {
                arg = ((ThreadLocal<?>) arg).get();
            } else {
                return arg;
            }
        }
    }
}

@@ -374,12 +374,8 @@
 ns, 
-and 
 Thre
@@ -382,16 +382,372 @@
 adLocals
+, and%0A * Enum values. Users can extend DefaultArgumentResolver by overriding %7B@link #canResolveCustomType(Object)%7D and%0A * %7B@link #resolveCustomType(Object)%7D to handle resolving types that are not handled by DefaultArgumentResolver, or to%0A * handle one of the default types in a different way (for example, to resolve Enums using ordinals instead of names).
 %0A */%0Apub
@@ -907,24 +907,122 @@
          if 
+(canResolveCustomType(arg)) %7B%0A                arg = resolveCustomType(arg);%0A            %7D else if 
 (arg instanc
@@ -1527,24 +1527,24 @@
           %7D%0A
-
         %7D%0A  
@@ -1546,11 +1546,1127 @@
  %7D%0A    %7D
+%0A%0A    /**%0A     * Users can override this method if they want to provide custom logic for resolving/unwrapping the given argument.%0A     *%0A     * @return true if the user wants to handle the argument using %7B@link #resolveCustomType(Object)%7D, false if the%0A     * default resolution logic should be used for this argument%0A     */%0A    protected boolean canResolveCustomType(Object arg) %7B%0A        return false;%0A    %7D%0A%0A    /**%0A     * Users can override this method if they want to provide custom logic for resolving/unwrapping the given argument.%0A     * This method will only be called if %7B@link #canResolveCustomType(Object)%7D returns true for some argument.%0A     *%0A     * @return the result of resolving/unwrapping the given argument.%0A     */%0A    protected Object resolveCustomType(Object arg) %7B%0A        throw new UnsupportedOperationException(%22DefaultArgumentResolver#resolveCustomType unimplemented. This %22%0A                + %22instance of DefaultArgumentResolver declared it could handle a type by returning true in %22%0A                + %22canResolveCustomType, but did not override resolveCustomType to resolve it.%22);%0A    %7D
 %0A%7D%0A

Make DefaultArgumentResolver extensible