All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pocketknife.PocketKnife Maven / Gradle / Ivy

The newest version!
package pocketknife;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import pocketknife.internal.BundleBinding;
import pocketknife.internal.IntentBinding;
import pocketknife.internal.Memoizer;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import static pocketknife.internal.GeneratedAdapters.ANDROID_PREFIX;
import static pocketknife.internal.GeneratedAdapters.BUNDLE_ADAPTER_SUFFIX;
import static pocketknife.internal.GeneratedAdapters.INTENT_ADAPTER_SUFFIX;
import static pocketknife.internal.GeneratedAdapters.JAVA_PREFIX;


public final class PocketKnife {
    private static final String TAG = "PocketKnife";
    private static boolean debug;

    private PocketKnife() {
        throw new AssertionError("No instances.");
    }

    /**
     * Control whether debug logging ins enabled
     */
    public static void setDebug(boolean debug) {
        PocketKnife.debug = debug;
    }

    /**
     * Save annotated fields in the specified {@code target} to the {@link Bundle}.
     *
     * @param target Target class for field saving.
     * @param bundle Bundle to save the field values.
     */
    public static  void saveInstanceState(T target, Bundle bundle) {
        @SuppressWarnings("unchecked")
        BundleBinding binding = (BundleBinding) getBundleBinding(target.getClass().getClassLoader(), target.getClass());
        if (binding != null) {
            binding.saveInstanceState(target, bundle);
        }
    }

    /**
     * Restore annotated fields in the specified {@code target} from the {@link Bundle}.
     *
     * @param target Target class to restore fields
     * @param bundle Bundle to restore field values.
     */
    public static  void restoreInstanceState(T target, Bundle bundle) {
        @SuppressWarnings("unchecked")
        BundleBinding binding = (BundleBinding) getBundleBinding(target.getClass().getClassLoader(), target.getClass());
        if (binding != null) {
            binding.restoreInstanceState(target, bundle);
        }
    }

    /**
     * Bind annotated fields in the specified {@link android.app.Fragment} from its arguments.
     *
     * @param fragment fragment to bind the arguments;
     */
    public static void bindArguments(android.app.Fragment fragment) {
        bindArguments(fragment, fragment.getArguments());
    }

    /**
     * Bind annotated fields in the specified {@link android.support.v4.app.Fragment} from its arguments.
     *
     * @param fragment fragment to bind the arguments;
     */
    public static void bindArguments(android.support.v4.app.Fragment fragment) {
        bindArguments(fragment, fragment.getArguments());
    }

    /**
     * Bind annotated fields in the specified {@code target} from the {@link android.os.Bundle}.
     *
     * @param target Target object for bind arguments
     * @param bundle Bundle containing arguments;
     */
    public static  void bindArguments(T target, Bundle bundle) {
        @SuppressWarnings("unchecked")
        BundleBinding binding = (BundleBinding) getBundleBinding(target.getClass().getClassLoader(), target.getClass());
        if (binding != null) {
            binding.bindArguments(target, bundle);
        }
    }

    /**
     * Bind annotated field in the specified {@link android.app.Activity} from its intent.
     *
     * @param activity activity to bind the extras.
     */
    public static void bindExtras(Activity activity) {
        bindExtras(activity, activity.getIntent());
    }

    /**
     * Bind annotated fields in the specified {@code target} from the {@link android.content.Intent}.
     *
     * @param target Target object to bind the extras.
     * @param intent Intent containing the extras.
     */
    public static  void bindExtras(T target, Intent intent) {
        @SuppressWarnings("unchecked")
        IntentBinding binding = (IntentBinding) getIntentBinding(target.getClass().getClassLoader(), target.getClass());
        if (binding != null) {
            binding.bindExtras(target, intent);
        }
    }

    private static BundleBinding getBundleBinding(ClassLoader classLoader, Class cls) {
        String clsName = cls.getName();
        if (clsName.startsWith(ANDROID_PREFIX) || clsName.startsWith(JAVA_PREFIX)) {
            if (debug) {
                Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
            }
            return null;
        }
        Class adapterClass = loadClass(classLoader, clsName.concat(BUNDLE_ADAPTER_SUFFIX));
        if (!adapterClass.equals(Void.class)) {
            if (debug) {
                Log.d(TAG, "Found loadable bundle adapter for " + clsName);
            }
            try {
                @SuppressWarnings("unchecked")
                Constructor> constructor = (Constructor>) adapterClass.getConstructor();
                return constructor.newInstance();
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException(
                        "Couldn't find default constructor in the generated bundle adapter for class "
                                + clsName);
            } catch (InvocationTargetException e) {
                throw new IllegalStateException(
                        "Could not create an instance of the bundle adapter for class " + clsName, e);
            } catch (InstantiationException e) {
                throw new IllegalStateException(
                        "Could not create an instance of the bundle adapter for class " + clsName, e);
            } catch (IllegalAccessException e) {
                throw new IllegalStateException(
                        "Could not create an instance of the bundle adapter for class " + clsName, e);
            }
        }
        // Search for Parent Class adapter
        if (debug) {
            Log.d(TAG, String.format("%s not found. Trying superclass %s", clsName, cls.getSuperclass().getName()));
        }
        return getBundleBinding(classLoader, cls.getSuperclass());
    }

    private static IntentBinding getIntentBinding(ClassLoader classLoader, Class cls) {
        String clsName = cls.getName();
        if (clsName.startsWith(ANDROID_PREFIX) || clsName.startsWith(JAVA_PREFIX)) {
            if (debug) {
                Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
            }
            return null;
        }
        Class adapterClass = loadClass(classLoader, clsName.concat(INTENT_ADAPTER_SUFFIX));
        if (!adapterClass.equals(Void.class)) {
            if (debug) {
                Log.d(TAG, "Found loadable intent adapter for " + clsName);
            }
            try {
                @SuppressWarnings("unchecked")
                Constructor> constructor = (Constructor>) adapterClass.getConstructor();
                return constructor.newInstance();
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException(
                        "Couldn't find default constructor in the generated intent adapter for class "
                                + clsName);
            } catch (InvocationTargetException e) {
                throw new IllegalStateException(
                        "Could not create an instance of the intent adapter for class " + clsName, e);
            } catch (InstantiationException e) {
                throw new IllegalStateException(
                        "Could not create an instance of the intent adapter for class " + clsName, e);
            } catch (IllegalAccessException e) {
                throw new IllegalStateException(
                        "Could not create an instance of the intent adapter for class " + clsName, e);
            }
        }
        // Search for Parent Class adapter
        if (debug) {
            Log.d(TAG, String.format("%s not found. Trying superclass %s", clsName, cls.getSuperclass().getName()));
        }
        return getIntentBinding(classLoader, cls.getSuperclass());
    }

    private static Class loadClass(ClassLoader classLoader, String name) {
        // a null classloader is the system classloader.
        if (classLoader == null) {
            if (debug) {
                Log.d(TAG, "Class loader is null using system class loader");
            }
            classLoader = ClassLoader.getSystemClassLoader();
        }
        return CACHES.get(classLoader).get(name);
    }

    private static final Memoizer>> CACHES = new Memoizer>>() {
        @Override
        protected Memoizer> create(final ClassLoader classLoader) {
            return new Memoizer>() {
                @Override
                protected Class create(String className) {
                    try {
                        Class cls = classLoader.loadClass(className);
                        if (debug) {
                            Log.d(TAG, "Successfully loaded class " + className);
                        }
                        return cls;
                    } catch (ClassNotFoundException e) {
                        if (debug) {
                            Log.d(TAG, "Failed to load class " + className);
                        }
                        return Void.class; // Cache the failure (negative case).
                    }
                }
            };
        }
    };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy