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

pl.ais.commons.bean.facade.Facade Maven / Gradle / Ivy

package pl.ais.commons.bean.facade;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import org.objenesis.ObjenesisHelper;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;

import static pl.ais.commons.bean.facade.ClassPredicates.inheritable;
import static pl.ais.commons.bean.facade.ClassPredicates.is;

/**
 * Provides set of methods usable for creating facades.
 *
 * @author Warlock, AIS.PL
 * @since 1.0.1
 */
@Immutable
public final class Facade {

    private Facade() {
        throw new AssertionError("Creation of " + getClass().getName() + " instances is forbidden.");
    }

    private static  Class determineSuperclass(@Nonnull final Class candidate) {
        return is(candidate, inheritable()) ? candidate : determineSuperclass(candidate.getSuperclass());
    }

    /**
     * Creates and returns the facade (proxy) built over given instance of class {@literal T}.
     *
     * @param instance instance to be proxied
     * @param listener property traverse listener to be used for the facade
     * @param       superclass of {@literal T} which will be extended by the facade
     * @param       type of the instance to be proxied
     * @return newly created facade (proxy) build over given instance of class {@literal T}
     */
    @SuppressWarnings("unchecked")
    public static  S over(@Nonnull final T instance, final TraverseListener listener) {

        // Create CGLIB Enhancer using the instance class as superclass of the proxy we intend to create, ...
        final Class superclass = determineSuperclass((Class) instance.getClass());
        final Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(superclass);

        // ... specify set of interfaces to be implemented by the proxy, ...
        enhancer.setInterfaces(superclass.isInterface() ? new Class[] {superclass} : superclass.getInterfaces());

        // ... define the type of callback to be used, ...
        enhancer.setCallbackType(DelegatingMethodInterceptor.class);

        // ... and created the proxied class (skipping creating the instance for now).
        final Class proxiedClass = enhancer.createClass();

        // Now prepare to create an instance of the proxied class, register callbacks and the class loader, ...
        Enhancer.registerCallbacks(proxiedClass, new Callback[] {new DelegatingMethodInterceptor(instance, listener)});
        enhancer.setClassLoader(superclass.getClassLoader());

        // ... and do the dirty work.
        return ObjenesisHelper.newInstance(proxiedClass);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy